diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-11 16:22:22 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-11 16:22:22 -0400 |
commit | de34f4da7f62ff59ac6e1ef320b0fcfa3296fce3 (patch) | |
tree | 88b5db2fc7fbbb0353edd8447a832a5225a49d01 /drivers/media | |
parent | 56e520c7a0a490b63b042b047ec9659fc08762a4 (diff) | |
parent | 9fce0c226536fc36c7fb0a80000ca38a995be43e (diff) |
Merge tag 'media/v4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- Documentation improvements: conversion of all non-DocBook documents
to Sphinx and lots of fixes to the uAPI media book
- New PCI driver for Techwell TW5864 media grabber boards
- New SoC driver for ATMEL Image Sensor Controller
- Removal of some obsolete SoC drivers (s5p-tv driver and soc_camera
drivers)
- Addition of ST CEC driver
- Lots of drivers fixes, improvements and additions
* tag 'media/v4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (464 commits)
[media] ttusb_dec: avoid the risk of go past buffer
[media] cx23885: Fix some smatch warnings
[media] si2165: switch to regmap
[media] si2165: use i2c_client->dev instead of i2c_adapter->dev for logging
[media] si2165: Remove legacy attach
[media] cx231xx: attach si2165 driver via i2c_client
[media] cx231xx: Prepare for attaching new style i2c_client DVB demod drivers
[media] cx23885: attach si2165 driver via i2c_client
[media] si2165: support i2c_client attach
[media] si2165: avoid division by zero
[media] rcar-vin: add R-Car gen2 fallback compatibility string
[media] lgdt3306a: remove 20*50 msec unnecessary timeout
[media] cx25821: Remove deprecated create_singlethread_workqueue
[media] cx25821: Drop Freeing of Workqueue
[media] cxd2841er: force 8MHz bandwidth for DVB-C if specified bw not supported
[media] redrat3: hardware-specific parameters
[media] redrat3: remove hw_timeout member
[media] cxd2841er: BER and SNR reading for ISDB-T
[media] dvb-usb: avoid link error with dib3000m{b,c|
[media] dvb-usb: split out common parts of dibusb
...
Diffstat (limited to 'drivers/media')
327 files changed, 16940 insertions, 13352 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 962f2a9a6614..7b8540291217 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig | |||
@@ -180,14 +180,14 @@ source "drivers/media/firewire/Kconfig" | |||
180 | # Common driver options | 180 | # Common driver options |
181 | source "drivers/media/common/Kconfig" | 181 | source "drivers/media/common/Kconfig" |
182 | 182 | ||
183 | comment "Media ancillary drivers (tuners, sensors, i2c, frontends)" | 183 | comment "Media ancillary drivers (tuners, sensors, i2c, spi, frontends)" |
184 | 184 | ||
185 | # | 185 | # |
186 | # Ancillary drivers (tuners, i2c, frontends) | 186 | # Ancillary drivers (tuners, i2c, spi, frontends) |
187 | # | 187 | # |
188 | 188 | ||
189 | config MEDIA_SUBDRV_AUTOSELECT | 189 | config MEDIA_SUBDRV_AUTOSELECT |
190 | bool "Autoselect ancillary drivers (tuners, sensors, i2c, frontends)" | 190 | bool "Autoselect ancillary drivers (tuners, sensors, i2c, spi, frontends)" |
191 | depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT || MEDIA_SDR_SUPPORT | 191 | depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT || MEDIA_SDR_SUPPORT |
192 | depends on HAS_IOMEM | 192 | depends on HAS_IOMEM |
193 | select I2C | 193 | select I2C |
@@ -216,6 +216,7 @@ config MEDIA_ATTACH | |||
216 | default MODULES | 216 | default MODULES |
217 | 217 | ||
218 | source "drivers/media/i2c/Kconfig" | 218 | source "drivers/media/i2c/Kconfig" |
219 | source "drivers/media/spi/Kconfig" | ||
219 | source "drivers/media/tuners/Kconfig" | 220 | source "drivers/media/tuners/Kconfig" |
220 | source "drivers/media/dvb-frontends/Kconfig" | 221 | source "drivers/media/dvb-frontends/Kconfig" |
221 | 222 | ||
diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 081a7866fd44..0deaa93efdee 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile | |||
@@ -32,6 +32,6 @@ obj-y += rc/ | |||
32 | # Finally, merge the drivers that require the core | 32 | # Finally, merge the drivers that require the core |
33 | # | 33 | # |
34 | 34 | ||
35 | obj-y += common/ platform/ pci/ usb/ mmc/ firewire/ | 35 | obj-y += common/ platform/ pci/ usb/ mmc/ firewire/ spi/ |
36 | obj-$(CONFIG_VIDEO_DEV) += radio/ | 36 | obj-$(CONFIG_VIDEO_DEV) += radio/ |
37 | 37 | ||
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 3ec3cebe62b9..1684810cab83 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | |||
@@ -504,14 +504,14 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b, | |||
504 | #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0)) | 504 | #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0)) |
505 | 505 | ||
506 | static const int bt601[3][3] = { | 506 | static const int bt601[3][3] = { |
507 | { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) }, | 507 | { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) }, |
508 | { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) }, | 508 | { COEFF(-0.1687, 224), COEFF(-0.3313, 224), COEFF(0.5, 224) }, |
509 | { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) }, | 509 | { COEFF(0.5, 224), COEFF(-0.4187, 224), COEFF(-0.0813, 224) }, |
510 | }; | 510 | }; |
511 | static const int bt601_full[3][3] = { | 511 | static const int bt601_full[3][3] = { |
512 | { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) }, | 512 | { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) }, |
513 | { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) }, | 513 | { COEFF(-0.1687, 255), COEFF(-0.3313, 255), COEFF(0.5, 255) }, |
514 | { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) }, | 514 | { COEFF(0.5, 255), COEFF(-0.4187, 255), COEFF(-0.0813, 255) }, |
515 | }; | 515 | }; |
516 | static const int rec709[3][3] = { | 516 | static const int rec709[3][3] = { |
517 | { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) }, | 517 | { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) }, |
@@ -558,7 +558,6 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b, | |||
558 | 558 | ||
559 | switch (tpg->real_ycbcr_enc) { | 559 | switch (tpg->real_ycbcr_enc) { |
560 | case V4L2_YCBCR_ENC_601: | 560 | case V4L2_YCBCR_ENC_601: |
561 | case V4L2_YCBCR_ENC_SYCC: | ||
562 | rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr); | 561 | rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr); |
563 | break; | 562 | break; |
564 | case V4L2_YCBCR_ENC_XV601: | 563 | case V4L2_YCBCR_ENC_XV601: |
@@ -674,7 +673,6 @@ static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr, | |||
674 | 673 | ||
675 | switch (tpg->real_ycbcr_enc) { | 674 | switch (tpg->real_ycbcr_enc) { |
676 | case V4L2_YCBCR_ENC_601: | 675 | case V4L2_YCBCR_ENC_601: |
677 | case V4L2_YCBCR_ENC_SYCC: | ||
678 | ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b); | 676 | ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b); |
679 | break; | 677 | break; |
680 | case V4L2_YCBCR_ENC_XV601: | 678 | case V4L2_YCBCR_ENC_XV601: |
diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h index 4b4c1da20f4b..aeda2b64931c 100644 --- a/drivers/media/dvb-core/demux.h +++ b/drivers/media/dvb-core/demux.h | |||
@@ -202,7 +202,7 @@ struct dmx_section_feed { | |||
202 | * | 202 | * |
203 | * This function callback prototype, provided by the client of the demux API, | 203 | * This function callback prototype, provided by the client of the demux API, |
204 | * is called from the demux code. The function is only called when filtering | 204 | * is called from the demux code. The function is only called when filtering |
205 | * on ae TS feed has been enabled using the start_filtering() function at | 205 | * on a TS feed has been enabled using the start_filtering\(\) function at |
206 | * the &dmx_demux. | 206 | * the &dmx_demux. |
207 | * Any TS packets that match the filter settings are copied to a circular | 207 | * Any TS packets that match the filter settings are copied to a circular |
208 | * buffer. The filtered TS packets are delivered to the client using this | 208 | * buffer. The filtered TS packets are delivered to the client using this |
@@ -243,8 +243,10 @@ struct dmx_section_feed { | |||
243 | * will also be sent to the hardware MPEG decoder. | 243 | * will also be sent to the hardware MPEG decoder. |
244 | * | 244 | * |
245 | * Return: | 245 | * Return: |
246 | * 0, on success; | 246 | * |
247 | * -EOVERFLOW, on buffer overflow. | 247 | * - 0, on success; |
248 | * | ||
249 | * - -EOVERFLOW, on buffer overflow. | ||
248 | */ | 250 | */ |
249 | typedef int (*dmx_ts_cb)(const u8 *buffer1, | 251 | typedef int (*dmx_ts_cb)(const u8 *buffer1, |
250 | size_t buffer1_length, | 252 | size_t buffer1_length, |
@@ -293,9 +295,9 @@ typedef int (*dmx_section_cb)(const u8 *buffer1, | |||
293 | size_t buffer2_len, | 295 | size_t buffer2_len, |
294 | struct dmx_section_filter *source); | 296 | struct dmx_section_filter *source); |
295 | 297 | ||
296 | /*--------------------------------------------------------------------------*/ | 298 | /* |
297 | /* DVB Front-End */ | 299 | * DVB Front-End |
298 | /*--------------------------------------------------------------------------*/ | 300 | */ |
299 | 301 | ||
300 | /** | 302 | /** |
301 | * enum dmx_frontend_source - Used to identify the type of frontend | 303 | * enum dmx_frontend_source - Used to identify the type of frontend |
@@ -349,15 +351,15 @@ enum dmx_demux_caps { | |||
349 | 351 | ||
350 | /* | 352 | /* |
351 | * Demux resource type identifier. | 353 | * Demux resource type identifier. |
352 | */ | 354 | */ |
353 | |||
354 | /* | ||
355 | * DMX_FE_ENTRY(): Casts elements in the list of registered | ||
356 | * front-ends from the generic type struct list_head | ||
357 | * to the type * struct dmx_frontend | ||
358 | *. | ||
359 | */ | ||
360 | 355 | ||
356 | /** | ||
357 | * DMX_FE_ENTRY - Casts elements in the list of registered | ||
358 | * front-ends from the generic type struct list_head | ||
359 | * to the type * struct dmx_frontend | ||
360 | * | ||
361 | * @list: list of struct dmx_frontend | ||
362 | */ | ||
361 | #define DMX_FE_ENTRY(list) \ | 363 | #define DMX_FE_ENTRY(list) \ |
362 | list_entry(list, struct dmx_frontend, connectivity_list) | 364 | list_entry(list, struct dmx_frontend, connectivity_list) |
363 | 365 | ||
@@ -551,7 +553,6 @@ enum dmx_demux_caps { | |||
551 | * 0 on success; | 553 | * 0 on success; |
552 | * -EINVAL on bad parameter. | 554 | * -EINVAL on bad parameter. |
553 | */ | 555 | */ |
554 | |||
555 | struct dmx_demux { | 556 | struct dmx_demux { |
556 | enum dmx_demux_caps capabilities; | 557 | enum dmx_demux_caps capabilities; |
557 | struct dmx_frontend *frontend; | 558 | struct dmx_frontend *frontend; |
@@ -581,15 +582,12 @@ struct dmx_demux { | |||
581 | 582 | ||
582 | int (*get_pes_pids)(struct dmx_demux *demux, u16 *pids); | 583 | int (*get_pes_pids)(struct dmx_demux *demux, u16 *pids); |
583 | 584 | ||
584 | /* private: Not used upstream and never documented */ | 585 | /* private: */ |
585 | #if 0 | 586 | |
586 | int (*get_caps)(struct dmx_demux *demux, struct dmx_caps *caps); | ||
587 | int (*set_source)(struct dmx_demux *demux, const dmx_source_t *src); | ||
588 | #endif | ||
589 | /* | 587 | /* |
590 | * private: Only used at av7110, to read some data from firmware. | 588 | * Only used at av7110, to read some data from firmware. |
591 | * As this was never documented, we have no clue about what's | 589 | * As this was never documented, we have no clue about what's |
592 | * there, and its usage on other drivers aren't encouraged. | 590 | * there, and its usage on other drivers aren't encouraged. |
593 | */ | 591 | */ |
594 | int (*get_stc)(struct dmx_demux *demux, unsigned int num, | 592 | int (*get_stc)(struct dmx_demux *demux, unsigned int num, |
595 | u64 *stc, unsigned int *base); | 593 | u64 *stc, unsigned int *base); |
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index be99c8dbc5f8..01511e5a5566 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c | |||
@@ -1969,17 +1969,9 @@ static int dvb_frontend_ioctl_properties(struct file *file, | |||
1969 | if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) | 1969 | if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) |
1970 | return -EINVAL; | 1970 | return -EINVAL; |
1971 | 1971 | ||
1972 | tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL); | 1972 | tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); |
1973 | if (!tvp) { | 1973 | if (IS_ERR(tvp)) |
1974 | err = -ENOMEM; | 1974 | return PTR_ERR(tvp); |
1975 | goto out; | ||
1976 | } | ||
1977 | |||
1978 | if (copy_from_user(tvp, (void __user *)tvps->props, | ||
1979 | tvps->num * sizeof(struct dtv_property))) { | ||
1980 | err = -EFAULT; | ||
1981 | goto out; | ||
1982 | } | ||
1983 | 1975 | ||
1984 | for (i = 0; i < tvps->num; i++) { | 1976 | for (i = 0; i < tvps->num; i++) { |
1985 | err = dtv_property_process_set(fe, tvp + i, file); | 1977 | err = dtv_property_process_set(fe, tvp + i, file); |
@@ -2002,17 +1994,9 @@ static int dvb_frontend_ioctl_properties(struct file *file, | |||
2002 | if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) | 1994 | if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) |
2003 | return -EINVAL; | 1995 | return -EINVAL; |
2004 | 1996 | ||
2005 | tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL); | 1997 | tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); |
2006 | if (!tvp) { | 1998 | if (IS_ERR(tvp)) |
2007 | err = -ENOMEM; | 1999 | return PTR_ERR(tvp); |
2008 | goto out; | ||
2009 | } | ||
2010 | |||
2011 | if (copy_from_user(tvp, (void __user *)tvps->props, | ||
2012 | tvps->num * sizeof(struct dtv_property))) { | ||
2013 | err = -EFAULT; | ||
2014 | goto out; | ||
2015 | } | ||
2016 | 2000 | ||
2017 | /* | 2001 | /* |
2018 | * Let's use our own copy of property cache, in order to | 2002 | * Let's use our own copy of property cache, in order to |
diff --git a/drivers/media/dvb-core/dvb_math.h b/drivers/media/dvb-core/dvb_math.h index 2f0326674ca6..4d11d3529c14 100644 --- a/drivers/media/dvb-core/dvb_math.h +++ b/drivers/media/dvb-core/dvb_math.h | |||
@@ -25,7 +25,7 @@ | |||
25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
26 | 26 | ||
27 | /** | 27 | /** |
28 | * cintlog2 - computes log2 of a value; the result is shifted left by 24 bits | 28 | * intlog2 - computes log2 of a value; the result is shifted left by 24 bits |
29 | * | 29 | * |
30 | * @value: The value (must be != 0) | 30 | * @value: The value (must be != 0) |
31 | * | 31 | * |
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb-core/dvb_ringbuffer.h index 8af642399f1e..bbe94873d44d 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.h +++ b/drivers/media/dvb-core/dvb_ringbuffer.h | |||
@@ -18,10 +18,6 @@ | |||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | * GNU Lesser General Public License for more details. | 20 | * GNU Lesser General Public License for more details. |
21 | * | ||
22 | * You should have received a copy of the GNU Lesser General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
25 | */ | 21 | */ |
26 | 22 | ||
27 | #ifndef _DVB_RINGBUFFER_H_ | 23 | #ifndef _DVB_RINGBUFFER_H_ |
@@ -30,6 +26,18 @@ | |||
30 | #include <linux/spinlock.h> | 26 | #include <linux/spinlock.h> |
31 | #include <linux/wait.h> | 27 | #include <linux/wait.h> |
32 | 28 | ||
29 | /** | ||
30 | * struct dvb_ringbuffer - Describes a ring buffer used at DVB framework | ||
31 | * | ||
32 | * @data: Area were the ringbuffer data is written | ||
33 | * @size: size of the ringbuffer | ||
34 | * @pread: next position to read | ||
35 | * @pwrite: next position to write | ||
36 | * @error: used by ringbuffer clients to indicate that an error happened. | ||
37 | * @queue: Wait queue used by ringbuffer clients to indicate when buffer | ||
38 | * was filled | ||
39 | * @lock: Spinlock used to protect the ringbuffer | ||
40 | */ | ||
33 | struct dvb_ringbuffer { | 41 | struct dvb_ringbuffer { |
34 | u8 *data; | 42 | u8 *data; |
35 | ssize_t size; | 43 | ssize_t size; |
@@ -43,99 +51,161 @@ struct dvb_ringbuffer { | |||
43 | 51 | ||
44 | #define DVB_RINGBUFFER_PKTHDRSIZE 3 | 52 | #define DVB_RINGBUFFER_PKTHDRSIZE 3 |
45 | 53 | ||
54 | /** | ||
55 | * dvb_ringbuffer_init - initialize ring buffer, lock and queue | ||
56 | * | ||
57 | * @rbuf: pointer to struct dvb_ringbuffer | ||
58 | * @data: pointer to the buffer where the data will be stored | ||
59 | * @len: bytes from ring buffer into @buf | ||
60 | */ | ||
61 | extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, | ||
62 | size_t len); | ||
46 | 63 | ||
47 | /* | 64 | /** |
48 | * Notes: | 65 | * dvb_ringbuffer_empty - test whether buffer is empty |
49 | * ------ | 66 | * |
50 | * (1) For performance reasons read and write routines don't check buffer sizes | 67 | * @rbuf: pointer to struct dvb_ringbuffer |
51 | * and/or number of bytes free/available. This has to be done before these | 68 | */ |
52 | * routines are called. For example: | ||
53 | * | ||
54 | * *** write @buflen: bytes *** | ||
55 | * free = dvb_ringbuffer_free(rbuf); | ||
56 | * if (free >= buflen) | ||
57 | * count = dvb_ringbuffer_write(rbuf, buffer, buflen); | ||
58 | * else | ||
59 | * ... | ||
60 | * | ||
61 | * *** read min. 1000, max. @bufsize: bytes *** | ||
62 | * avail = dvb_ringbuffer_avail(rbuf); | ||
63 | * if (avail >= 1000) | ||
64 | * count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize)); | ||
65 | * else | ||
66 | * ... | ||
67 | * | ||
68 | * (2) If there is exactly one reader and one writer, there is no need | ||
69 | * to lock read or write operations. | ||
70 | * Two or more readers must be locked against each other. | ||
71 | * Flushing the buffer counts as a read operation. | ||
72 | * Resetting the buffer counts as a read and write operation. | ||
73 | * Two or more writers must be locked against each other. | ||
74 | */ | ||
75 | |||
76 | /* initialize ring buffer, lock and queue */ | ||
77 | extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len); | ||
78 | |||
79 | /* test whether buffer is empty */ | ||
80 | extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf); | 69 | extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf); |
81 | 70 | ||
82 | /* return the number of free bytes in the buffer */ | 71 | /** |
72 | * dvb_ringbuffer_free - returns the number of free bytes in the buffer | ||
73 | * | ||
74 | * @rbuf: pointer to struct dvb_ringbuffer | ||
75 | * | ||
76 | * Return: number of free bytes in the buffer | ||
77 | */ | ||
83 | extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf); | 78 | extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf); |
84 | 79 | ||
85 | /* return the number of bytes waiting in the buffer */ | 80 | /** |
81 | * dvb_ringbuffer_avail - returns the number of bytes waiting in the buffer | ||
82 | * | ||
83 | * @rbuf: pointer to struct dvb_ringbuffer | ||
84 | * | ||
85 | * Return: number of bytes waiting in the buffer | ||
86 | */ | ||
86 | extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf); | 87 | extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf); |
87 | 88 | ||
88 | 89 | /** | |
89 | /* | 90 | * dvb_ringbuffer_reset - resets the ringbuffer to initial state |
90 | * Reset the read and write pointers to zero and flush the buffer | 91 | * |
92 | * @rbuf: pointer to struct dvb_ringbuffer | ||
93 | * | ||
94 | * Resets the read and write pointers to zero and flush the buffer. | ||
95 | * | ||
91 | * This counts as a read and write operation | 96 | * This counts as a read and write operation |
92 | */ | 97 | */ |
93 | extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf); | 98 | extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf); |
94 | 99 | ||
100 | /* | ||
101 | * read routines & macros | ||
102 | */ | ||
95 | 103 | ||
96 | /* read routines & macros */ | 104 | /** |
97 | /* ---------------------- */ | 105 | * dvb_ringbuffer_flush - flush buffer |
98 | /* flush buffer */ | 106 | * |
107 | * @rbuf: pointer to struct dvb_ringbuffer | ||
108 | */ | ||
99 | extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf); | 109 | extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf); |
100 | 110 | ||
101 | /* flush buffer protected by spinlock and wake-up waiting task(s) */ | 111 | /** |
112 | * dvb_ringbuffer_flush_spinlock_wakeup- flush buffer protected by spinlock | ||
113 | * and wake-up waiting task(s) | ||
114 | * | ||
115 | * @rbuf: pointer to struct dvb_ringbuffer | ||
116 | */ | ||
102 | extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf); | 117 | extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf); |
103 | 118 | ||
104 | /* peek at byte @offs: in the buffer */ | 119 | /** |
105 | #define DVB_RINGBUFFER_PEEK(rbuf,offs) \ | 120 | * DVB_RINGBUFFER_PEEK - peek at byte @offs in the buffer |
106 | (rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size] | 121 | * |
122 | * @rbuf: pointer to struct dvb_ringbuffer | ||
123 | * @offs: offset inside the ringbuffer | ||
124 | */ | ||
125 | #define DVB_RINGBUFFER_PEEK(rbuf, offs) \ | ||
126 | ((rbuf)->data[((rbuf)->pread + (offs)) % (rbuf)->size]) | ||
107 | 127 | ||
108 | /* advance read ptr by @num: bytes */ | 128 | /** |
109 | #define DVB_RINGBUFFER_SKIP(rbuf,num) \ | 129 | * DVB_RINGBUFFER_SKIP - advance read ptr by @num bytes |
110 | (rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size | 130 | * |
131 | * @rbuf: pointer to struct dvb_ringbuffer | ||
132 | * @num: number of bytes to advance | ||
133 | */ | ||
134 | #define DVB_RINGBUFFER_SKIP(rbuf, num) {\ | ||
135 | (rbuf)->pread = ((rbuf)->pread + (num)) % (rbuf)->size;\ | ||
136 | } | ||
111 | 137 | ||
112 | /* | 138 | /** |
113 | * read @len: bytes from ring buffer into @buf: | 139 | * dvb_ringbuffer_read_user - Reads a buffer into an user pointer |
114 | * @usermem: specifies whether @buf: resides in user space | 140 | * |
115 | * returns number of bytes transferred or -EFAULT | 141 | * @rbuf: pointer to struct dvb_ringbuffer |
142 | * @buf: pointer to the buffer where the data will be stored | ||
143 | * @len: bytes from ring buffer into @buf | ||
144 | * | ||
145 | * This variant assumes that the buffer is a memory at the userspace. So, | ||
146 | * it will internally call copy_to_user(). | ||
147 | * | ||
148 | * Return: number of bytes transferred or -EFAULT | ||
116 | */ | 149 | */ |
117 | extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, | 150 | extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, |
118 | u8 __user *buf, size_t len); | 151 | u8 __user *buf, size_t len); |
152 | |||
153 | /** | ||
154 | * dvb_ringbuffer_read - Reads a buffer into a pointer | ||
155 | * | ||
156 | * @rbuf: pointer to struct dvb_ringbuffer | ||
157 | * @buf: pointer to the buffer where the data will be stored | ||
158 | * @len: bytes from ring buffer into @buf | ||
159 | * | ||
160 | * This variant assumes that the buffer is a memory at the Kernel space | ||
161 | * | ||
162 | * Return: number of bytes transferred or -EFAULT | ||
163 | */ | ||
119 | extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, | 164 | extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, |
120 | u8 *buf, size_t len); | 165 | u8 *buf, size_t len); |
121 | 166 | ||
122 | |||
123 | /* write routines & macros */ | ||
124 | /* ----------------------- */ | ||
125 | /* write single byte to ring buffer */ | ||
126 | #define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte) \ | ||
127 | { (rbuf)->data[(rbuf)->pwrite]=(byte); \ | ||
128 | (rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; } | ||
129 | /* | 167 | /* |
130 | * write @len: bytes to ring buffer | 168 | * write routines & macros |
131 | * @usermem: specifies whether @buf: resides in user space | 169 | */ |
132 | * returns number of bytes transferred or -EFAULT | 170 | |
133 | */ | 171 | /** |
172 | * DVB_RINGBUFFER_WRITE_BYTE - write single byte to ring buffer | ||
173 | * | ||
174 | * @rbuf: pointer to struct dvb_ringbuffer | ||
175 | * @byte: byte to write | ||
176 | */ | ||
177 | #define DVB_RINGBUFFER_WRITE_BYTE(rbuf, byte) \ | ||
178 | { (rbuf)->data[(rbuf)->pwrite] = (byte); \ | ||
179 | (rbuf)->pwrite = ((rbuf)->pwrite + 1) % (rbuf)->size; } | ||
180 | |||
181 | /** | ||
182 | * dvb_ringbuffer_write - Writes a buffer into the ringbuffer | ||
183 | * | ||
184 | * @rbuf: pointer to struct dvb_ringbuffer | ||
185 | * @buf: pointer to the buffer where the data will be read | ||
186 | * @len: bytes from ring buffer into @buf | ||
187 | * | ||
188 | * This variant assumes that the buffer is a memory at the Kernel space | ||
189 | * | ||
190 | * return: number of bytes transferred or -EFAULT | ||
191 | */ | ||
134 | extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, | 192 | extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, |
135 | size_t len); | 193 | size_t len); |
136 | extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, | ||
137 | const u8 __user *buf, size_t len); | ||
138 | 194 | ||
195 | /** | ||
196 | * dvb_ringbuffer_write_user - Writes a buffer received via an user pointer | ||
197 | * | ||
198 | * @rbuf: pointer to struct dvb_ringbuffer | ||
199 | * @buf: pointer to the buffer where the data will be read | ||
200 | * @len: bytes from ring buffer into @buf | ||
201 | * | ||
202 | * This variant assumes that the buffer is a memory at the userspace. So, | ||
203 | * it will internally call copy_from_user(). | ||
204 | * | ||
205 | * Return: number of bytes transferred or -EFAULT | ||
206 | */ | ||
207 | extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, | ||
208 | const u8 __user *buf, size_t len); | ||
139 | 209 | ||
140 | /** | 210 | /** |
141 | * dvb_ringbuffer_pkt_write - Write a packet into the ringbuffer. | 211 | * dvb_ringbuffer_pkt_write - Write a packet into the ringbuffer. |
@@ -143,9 +213,10 @@ extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, | |||
143 | * @rbuf: Ringbuffer to write to. | 213 | * @rbuf: Ringbuffer to write to. |
144 | * @buf: Buffer to write. | 214 | * @buf: Buffer to write. |
145 | * @len: Length of buffer (currently limited to 65535 bytes max). | 215 | * @len: Length of buffer (currently limited to 65535 bytes max). |
146 | * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL. | 216 | * |
217 | * Return: Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL. | ||
147 | */ | 218 | */ |
148 | extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, | 219 | extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8 *buf, |
149 | size_t len); | 220 | size_t len); |
150 | 221 | ||
151 | /** | 222 | /** |
@@ -157,7 +228,7 @@ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, | |||
157 | * @buf: Destination buffer for data. | 228 | * @buf: Destination buffer for data. |
158 | * @len: Size of destination buffer. | 229 | * @len: Size of destination buffer. |
159 | * | 230 | * |
160 | * returns Number of bytes read, or -EFAULT. | 231 | * Return: Number of bytes read, or -EFAULT. |
161 | * | 232 | * |
162 | * .. note:: | 233 | * .. note:: |
163 | * | 234 | * |
@@ -167,7 +238,7 @@ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, | |||
167 | */ | 238 | */ |
168 | extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, | 239 | extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, |
169 | size_t idx, | 240 | size_t idx, |
170 | int offset, u8 __user *buf, | 241 | int offset, u8 __user *buf, |
171 | size_t len); | 242 | size_t len); |
172 | 243 | ||
173 | /** | 244 | /** |
@@ -181,7 +252,7 @@ extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, | |||
181 | * @buf: Destination buffer for data. | 252 | * @buf: Destination buffer for data. |
182 | * @len: Size of destination buffer. | 253 | * @len: Size of destination buffer. |
183 | * | 254 | * |
184 | * returns Number of bytes read, or -EFAULT. | 255 | * Return: Number of bytes read, or -EFAULT. |
185 | */ | 256 | */ |
186 | extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, | 257 | extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, |
187 | int offset, u8 *buf, size_t len); | 258 | int offset, u8 *buf, size_t len); |
@@ -199,10 +270,11 @@ extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx); | |||
199 | * | 270 | * |
200 | * @rbuf: Ringbuffer concerned. | 271 | * @rbuf: Ringbuffer concerned. |
201 | * @idx: Previous packet index, or -1 to return the first packet index. | 272 | * @idx: Previous packet index, or -1 to return the first packet index. |
202 | * @pktlen: On success, will be updated to contain the length of the packet in bytes. | 273 | * @pktlen: On success, will be updated to contain the length of the packet |
274 | * in bytes. | ||
203 | * returns Packet index (if >=0), or -1 if no packets available. | 275 | * returns Packet index (if >=0), or -1 if no packets available. |
204 | */ | 276 | */ |
205 | extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen); | 277 | extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, |
206 | 278 | size_t idx, size_t *pktlen); | |
207 | 279 | ||
208 | #endif /* _DVB_RINGBUFFER_H_ */ | 280 | #endif /* _DVB_RINGBUFFER_H_ */ |
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index c645aa81f423..012225587c25 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig | |||
@@ -67,6 +67,7 @@ config DVB_TDA18271C2DD | |||
67 | config DVB_SI2165 | 67 | config DVB_SI2165 |
68 | tristate "Silicon Labs si2165 based" | 68 | tristate "Silicon Labs si2165 based" |
69 | depends on DVB_CORE && I2C | 69 | depends on DVB_CORE && I2C |
70 | select REGMAP_I2C | ||
70 | default m if !MEDIA_SUBDRV_AUTOSELECT | 71 | default m if !MEDIA_SUBDRV_AUTOSELECT |
71 | help | 72 | help |
72 | A DVB-C/T demodulator. | 73 | A DVB-C/T demodulator. |
@@ -463,6 +464,7 @@ config DVB_STV0367 | |||
463 | config DVB_CXD2820R | 464 | config DVB_CXD2820R |
464 | tristate "Sony CXD2820R" | 465 | tristate "Sony CXD2820R" |
465 | depends on DVB_CORE && I2C | 466 | depends on DVB_CORE && I2C |
467 | select REGMAP_I2C | ||
466 | default m if !MEDIA_SUBDRV_AUTOSELECT | 468 | default m if !MEDIA_SUBDRV_AUTOSELECT |
467 | help | 469 | help |
468 | Say Y when you want to support this frontend. | 470 | Say Y when you want to support this frontend. |
diff --git a/drivers/media/dvb-frontends/ascot2e.c b/drivers/media/dvb-frontends/ascot2e.c index 8cc8c4597b6a..ad304eed656d 100644 --- a/drivers/media/dvb-frontends/ascot2e.c +++ b/drivers/media/dvb-frontends/ascot2e.c | |||
@@ -464,7 +464,7 @@ static int ascot2e_get_frequency(struct dvb_frontend *fe, u32 *frequency) | |||
464 | return 0; | 464 | return 0; |
465 | } | 465 | } |
466 | 466 | ||
467 | static struct dvb_tuner_ops ascot2e_tuner_ops = { | 467 | static const struct dvb_tuner_ops ascot2e_tuner_ops = { |
468 | .info = { | 468 | .info = { |
469 | .name = "Sony ASCOT2E", | 469 | .name = "Sony ASCOT2E", |
470 | .frequency_min = 1000000, | 470 | .frequency_min = 1000000, |
diff --git a/drivers/media/dvb-frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h index 56d42760263d..d77afe0b8a9e 100644 --- a/drivers/media/dvb-frontends/cxd2820r.h +++ b/drivers/media/dvb-frontends/cxd2820r.h | |||
@@ -37,6 +37,32 @@ | |||
37 | #define CXD2820R_TS_PARALLEL 0x30 | 37 | #define CXD2820R_TS_PARALLEL 0x30 |
38 | #define CXD2820R_TS_PARALLEL_MSB 0x70 | 38 | #define CXD2820R_TS_PARALLEL_MSB 0x70 |
39 | 39 | ||
40 | /* | ||
41 | * I2C address: 0x6c, 0x6d | ||
42 | */ | ||
43 | |||
44 | /** | ||
45 | * struct cxd2820r_platform_data - Platform data for the cxd2820r driver | ||
46 | * @ts_mode: TS mode. | ||
47 | * @ts_clk_inv: TS clock inverted. | ||
48 | * @if_agc_polarity: IF AGC polarity. | ||
49 | * @spec_inv: Input spectrum inverted. | ||
50 | * @gpio_chip_base: GPIO. | ||
51 | * @get_dvb_frontend: Get DVB frontend. | ||
52 | */ | ||
53 | |||
54 | struct cxd2820r_platform_data { | ||
55 | u8 ts_mode; | ||
56 | bool ts_clk_inv; | ||
57 | bool if_agc_polarity; | ||
58 | bool spec_inv; | ||
59 | int **gpio_chip_base; | ||
60 | |||
61 | struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); | ||
62 | /* private: For legacy media attach wrapper. Do not set value. */ | ||
63 | bool attach_in_use; | ||
64 | }; | ||
65 | |||
40 | struct cxd2820r_config { | 66 | struct cxd2820r_config { |
41 | /* Demodulator I2C address. | 67 | /* Demodulator I2C address. |
42 | * Driver determines DVB-C slave I2C address automatically from master | 68 | * Driver determines DVB-C slave I2C address automatically from master |
diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index a674a6312c38..d75b0776d5b5 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c | |||
@@ -24,12 +24,12 @@ | |||
24 | int cxd2820r_set_frontend_c(struct dvb_frontend *fe) | 24 | int cxd2820r_set_frontend_c(struct dvb_frontend *fe) |
25 | { | 25 | { |
26 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 26 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
27 | struct i2c_client *client = priv->client[0]; | ||
27 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 28 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
28 | int ret, i; | 29 | int ret; |
30 | unsigned int utmp; | ||
29 | u8 buf[2]; | 31 | u8 buf[2]; |
30 | u32 if_freq; | 32 | u32 if_frequency; |
31 | u16 if_ctl; | ||
32 | u64 num; | ||
33 | struct reg_val_mask tab[] = { | 33 | struct reg_val_mask tab[] = { |
34 | { 0x00080, 0x01, 0xff }, | 34 | { 0x00080, 0x01, 0xff }, |
35 | { 0x00081, 0x05, 0xff }, | 35 | { 0x00081, 0x05, 0xff }, |
@@ -43,25 +43,24 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) | |||
43 | { 0x10059, 0x50, 0xff }, | 43 | { 0x10059, 0x50, 0xff }, |
44 | { 0x10087, 0x0c, 0x3c }, | 44 | { 0x10087, 0x0c, 0x3c }, |
45 | { 0x1008b, 0x07, 0xff }, | 45 | { 0x1008b, 0x07, 0xff }, |
46 | { 0x1001f, priv->cfg.if_agc_polarity << 7, 0x80 }, | 46 | { 0x1001f, priv->if_agc_polarity << 7, 0x80 }, |
47 | { 0x10070, priv->cfg.ts_mode, 0xff }, | 47 | { 0x10070, priv->ts_mode, 0xff }, |
48 | { 0x10071, !priv->cfg.ts_clock_inv << 4, 0x10 }, | 48 | { 0x10071, !priv->ts_clk_inv << 4, 0x10 }, |
49 | }; | 49 | }; |
50 | 50 | ||
51 | dev_dbg(&priv->i2c->dev, "%s: frequency=%d symbol_rate=%d\n", __func__, | 51 | dev_dbg(&client->dev, |
52 | c->frequency, c->symbol_rate); | 52 | "delivery_system=%d modulation=%d frequency=%u symbol_rate=%u inversion=%d\n", |
53 | c->delivery_system, c->modulation, c->frequency, | ||
54 | c->symbol_rate, c->inversion); | ||
53 | 55 | ||
54 | /* program tuner */ | 56 | /* program tuner */ |
55 | if (fe->ops.tuner_ops.set_params) | 57 | if (fe->ops.tuner_ops.set_params) |
56 | fe->ops.tuner_ops.set_params(fe); | 58 | fe->ops.tuner_ops.set_params(fe); |
57 | 59 | ||
58 | if (priv->delivery_system != SYS_DVBC_ANNEX_A) { | 60 | if (priv->delivery_system != SYS_DVBC_ANNEX_A) { |
59 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | 61 | ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab)); |
60 | ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, | 62 | if (ret) |
61 | tab[i].val, tab[i].mask); | 63 | goto error; |
62 | if (ret) | ||
63 | goto error; | ||
64 | } | ||
65 | } | 64 | } |
66 | 65 | ||
67 | priv->delivery_system = SYS_DVBC_ANNEX_A; | 66 | priv->delivery_system = SYS_DVBC_ANNEX_A; |
@@ -69,35 +68,33 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) | |||
69 | 68 | ||
70 | /* program IF frequency */ | 69 | /* program IF frequency */ |
71 | if (fe->ops.tuner_ops.get_if_frequency) { | 70 | if (fe->ops.tuner_ops.get_if_frequency) { |
72 | ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); | 71 | ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); |
73 | if (ret) | 72 | if (ret) |
74 | goto error; | 73 | goto error; |
75 | } else | 74 | dev_dbg(&client->dev, "if_frequency=%u\n", if_frequency); |
76 | if_freq = 0; | 75 | } else { |
77 | 76 | ret = -EINVAL; | |
78 | dev_dbg(&priv->i2c->dev, "%s: if_freq=%d\n", __func__, if_freq); | 77 | goto error; |
79 | 78 | } | |
80 | num = if_freq / 1000; /* Hz => kHz */ | ||
81 | num *= 0x4000; | ||
82 | if_ctl = 0x4000 - DIV_ROUND_CLOSEST_ULL(num, 41000); | ||
83 | buf[0] = (if_ctl >> 8) & 0x3f; | ||
84 | buf[1] = (if_ctl >> 0) & 0xff; | ||
85 | 79 | ||
86 | ret = cxd2820r_wr_regs(priv, 0x10042, buf, 2); | 80 | utmp = 0x4000 - DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x4000, CXD2820R_CLK); |
81 | buf[0] = (utmp >> 8) & 0xff; | ||
82 | buf[1] = (utmp >> 0) & 0xff; | ||
83 | ret = regmap_bulk_write(priv->regmap[1], 0x0042, buf, 2); | ||
87 | if (ret) | 84 | if (ret) |
88 | goto error; | 85 | goto error; |
89 | 86 | ||
90 | ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08); | 87 | ret = regmap_write(priv->regmap[0], 0x00ff, 0x08); |
91 | if (ret) | 88 | if (ret) |
92 | goto error; | 89 | goto error; |
93 | 90 | ||
94 | ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01); | 91 | ret = regmap_write(priv->regmap[0], 0x00fe, 0x01); |
95 | if (ret) | 92 | if (ret) |
96 | goto error; | 93 | goto error; |
97 | 94 | ||
98 | return ret; | 95 | return ret; |
99 | error: | 96 | error: |
100 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 97 | dev_dbg(&client->dev, "failed=%d\n", ret); |
101 | return ret; | 98 | return ret; |
102 | } | 99 | } |
103 | 100 | ||
@@ -105,20 +102,24 @@ int cxd2820r_get_frontend_c(struct dvb_frontend *fe, | |||
105 | struct dtv_frontend_properties *c) | 102 | struct dtv_frontend_properties *c) |
106 | { | 103 | { |
107 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 104 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
105 | struct i2c_client *client = priv->client[0]; | ||
108 | int ret; | 106 | int ret; |
107 | unsigned int utmp; | ||
109 | u8 buf[2]; | 108 | u8 buf[2]; |
110 | 109 | ||
111 | ret = cxd2820r_rd_regs(priv, 0x1001a, buf, 2); | 110 | dev_dbg(&client->dev, "\n"); |
111 | |||
112 | ret = regmap_bulk_read(priv->regmap[1], 0x001a, buf, 2); | ||
112 | if (ret) | 113 | if (ret) |
113 | goto error; | 114 | goto error; |
114 | 115 | ||
115 | c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]); | 116 | c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]); |
116 | 117 | ||
117 | ret = cxd2820r_rd_reg(priv, 0x10019, &buf[0]); | 118 | ret = regmap_read(priv->regmap[1], 0x0019, &utmp); |
118 | if (ret) | 119 | if (ret) |
119 | goto error; | 120 | goto error; |
120 | 121 | ||
121 | switch ((buf[0] >> 0) & 0x07) { | 122 | switch ((utmp >> 0) & 0x07) { |
122 | case 0: | 123 | case 0: |
123 | c->modulation = QAM_16; | 124 | c->modulation = QAM_16; |
124 | break; | 125 | break; |
@@ -136,7 +137,7 @@ int cxd2820r_get_frontend_c(struct dvb_frontend *fe, | |||
136 | break; | 137 | break; |
137 | } | 138 | } |
138 | 139 | ||
139 | switch ((buf[0] >> 7) & 0x01) { | 140 | switch ((utmp >> 7) & 0x01) { |
140 | case 0: | 141 | case 0: |
141 | c->inversion = INVERSION_OFF; | 142 | c->inversion = INVERSION_OFF; |
142 | break; | 143 | break; |
@@ -147,167 +148,169 @@ int cxd2820r_get_frontend_c(struct dvb_frontend *fe, | |||
147 | 148 | ||
148 | return ret; | 149 | return ret; |
149 | error: | 150 | error: |
150 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 151 | dev_dbg(&client->dev, "failed=%d\n", ret); |
151 | return ret; | 152 | return ret; |
152 | } | 153 | } |
153 | 154 | ||
154 | int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber) | 155 | int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) |
155 | { | 156 | { |
156 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 157 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
158 | struct i2c_client *client = priv->client[0]; | ||
159 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
157 | int ret; | 160 | int ret; |
158 | u8 buf[3], start_ber = 0; | 161 | unsigned int utmp, utmp1, utmp2; |
159 | *ber = 0; | 162 | u8 buf[3]; |
160 | 163 | ||
161 | if (priv->ber_running) { | 164 | /* Lock detection */ |
162 | ret = cxd2820r_rd_regs(priv, 0x10076, buf, sizeof(buf)); | 165 | ret = regmap_bulk_read(priv->regmap[1], 0x0088, &buf[0], 1); |
163 | if (ret) | 166 | if (ret) |
164 | goto error; | 167 | goto error; |
168 | ret = regmap_bulk_read(priv->regmap[1], 0x0073, &buf[1], 1); | ||
169 | if (ret) | ||
170 | goto error; | ||
165 | 171 | ||
166 | if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) { | 172 | utmp1 = (buf[0] >> 0) & 0x01; |
167 | *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0]; | 173 | utmp2 = (buf[1] >> 3) & 0x01; |
168 | start_ber = 1; | 174 | |
169 | } | 175 | if (utmp1 == 1 && utmp2 == 1) { |
176 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
177 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | ||
178 | } else if (utmp1 == 1 || utmp2 == 1) { | ||
179 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
180 | FE_HAS_VITERBI | FE_HAS_SYNC; | ||
170 | } else { | 181 | } else { |
171 | priv->ber_running = true; | 182 | *status = 0; |
172 | start_ber = 1; | ||
173 | } | 183 | } |
174 | 184 | ||
175 | if (start_ber) { | 185 | dev_dbg(&client->dev, "status=%02x raw=%*ph sync=%u ts=%u\n", |
176 | /* (re)start BER */ | 186 | *status, 2, buf, utmp1, utmp2); |
177 | ret = cxd2820r_wr_reg(priv, 0x10079, 0x01); | ||
178 | if (ret) | ||
179 | goto error; | ||
180 | } | ||
181 | 187 | ||
182 | return ret; | 188 | /* Signal strength */ |
183 | error: | 189 | if (*status & FE_HAS_SIGNAL) { |
184 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 190 | unsigned int strength; |
185 | return ret; | ||
186 | } | ||
187 | 191 | ||
188 | int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe, | 192 | ret = regmap_bulk_read(priv->regmap[1], 0x0049, buf, 2); |
189 | u16 *strength) | 193 | if (ret) |
190 | { | 194 | goto error; |
191 | struct cxd2820r_priv *priv = fe->demodulator_priv; | ||
192 | int ret; | ||
193 | u8 buf[2]; | ||
194 | u16 tmp; | ||
195 | 195 | ||
196 | ret = cxd2820r_rd_regs(priv, 0x10049, buf, sizeof(buf)); | 196 | utmp = buf[0] << 8 | buf[1] << 0; |
197 | if (ret) | 197 | utmp = 511 - sign_extend32(utmp, 9); |
198 | goto error; | 198 | /* Scale value to 0x0000-0xffff */ |
199 | strength = utmp << 6 | utmp >> 4; | ||
199 | 200 | ||
200 | tmp = (buf[0] & 0x03) << 8 | buf[1]; | 201 | c->strength.len = 1; |
201 | tmp = (~tmp & 0x03ff); | 202 | c->strength.stat[0].scale = FE_SCALE_RELATIVE; |
203 | c->strength.stat[0].uvalue = strength; | ||
204 | } else { | ||
205 | c->strength.len = 1; | ||
206 | c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
207 | } | ||
202 | 208 | ||
203 | if (tmp == 512) | 209 | /* CNR */ |
204 | /* ~no signal */ | 210 | if (*status & FE_HAS_VITERBI) { |
205 | tmp = 0; | 211 | unsigned int cnr, const_a, const_b; |
206 | else if (tmp > 350) | ||
207 | tmp = 350; | ||
208 | 212 | ||
209 | /* scale value to 0x0000-0xffff */ | 213 | ret = regmap_read(priv->regmap[1], 0x0019, &utmp); |
210 | *strength = tmp * 0xffff / (350-0); | 214 | if (ret) |
215 | goto error; | ||
211 | 216 | ||
212 | return ret; | 217 | if (((utmp >> 0) & 0x03) % 2) { |
213 | error: | 218 | const_a = 8750; |
214 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 219 | const_b = 650; |
215 | return ret; | 220 | } else { |
216 | } | 221 | const_a = 9500; |
222 | const_b = 760; | ||
223 | } | ||
217 | 224 | ||
218 | int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr) | 225 | ret = regmap_read(priv->regmap[1], 0x004d, &utmp); |
219 | { | 226 | if (ret) |
220 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 227 | goto error; |
221 | int ret; | ||
222 | u8 tmp; | ||
223 | unsigned int A, B; | ||
224 | /* report SNR in dB * 10 */ | ||
225 | 228 | ||
226 | ret = cxd2820r_rd_reg(priv, 0x10019, &tmp); | 229 | #define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */ |
227 | if (ret) | 230 | if (utmp) |
228 | goto error; | 231 | cnr = div_u64((u64)(intlog2(const_b) - intlog2(utmp)) |
232 | * const_a, CXD2820R_LOG2_E_24); | ||
233 | else | ||
234 | cnr = 0; | ||
229 | 235 | ||
230 | if (((tmp >> 0) & 0x03) % 2) { | 236 | c->cnr.len = 1; |
231 | A = 875; | 237 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; |
232 | B = 650; | 238 | c->cnr.stat[0].svalue = cnr; |
233 | } else { | 239 | } else { |
234 | A = 950; | 240 | c->cnr.len = 1; |
235 | B = 760; | 241 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
236 | } | 242 | } |
237 | 243 | ||
238 | ret = cxd2820r_rd_reg(priv, 0x1004d, &tmp); | 244 | /* BER */ |
239 | if (ret) | 245 | if (*status & FE_HAS_SYNC) { |
240 | goto error; | 246 | unsigned int post_bit_error; |
241 | 247 | bool start_ber; | |
242 | #define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */ | ||
243 | if (tmp) | ||
244 | *snr = A * (intlog2(B / tmp) >> 5) / (CXD2820R_LOG2_E_24 >> 5) | ||
245 | / 10; | ||
246 | else | ||
247 | *snr = 0; | ||
248 | |||
249 | return ret; | ||
250 | error: | ||
251 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
252 | return ret; | ||
253 | } | ||
254 | 248 | ||
255 | int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks) | 249 | if (priv->ber_running) { |
256 | { | 250 | ret = regmap_bulk_read(priv->regmap[1], 0x0076, buf, 3); |
257 | *ucblocks = 0; | 251 | if (ret) |
258 | /* no way to read ? */ | 252 | goto error; |
259 | return 0; | ||
260 | } | ||
261 | 253 | ||
262 | int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status) | 254 | if ((buf[2] >> 7) & 0x01) { |
263 | { | 255 | post_bit_error = buf[2] << 16 | buf[1] << 8 | |
264 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 256 | buf[0] << 0; |
265 | int ret; | 257 | post_bit_error &= 0x0fffff; |
266 | u8 buf[2]; | 258 | start_ber = true; |
267 | *status = 0; | 259 | } else { |
260 | post_bit_error = 0; | ||
261 | start_ber = false; | ||
262 | } | ||
263 | } else { | ||
264 | post_bit_error = 0; | ||
265 | start_ber = true; | ||
266 | } | ||
268 | 267 | ||
269 | ret = cxd2820r_rd_regs(priv, 0x10088, buf, sizeof(buf)); | 268 | if (start_ber) { |
270 | if (ret) | 269 | ret = regmap_write(priv->regmap[1], 0x0079, 0x01); |
271 | goto error; | 270 | if (ret) |
271 | goto error; | ||
272 | priv->ber_running = true; | ||
273 | } | ||
272 | 274 | ||
273 | if (((buf[0] >> 0) & 0x01) == 1) { | 275 | priv->post_bit_error += post_bit_error; |
274 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
275 | FE_HAS_VITERBI | FE_HAS_SYNC; | ||
276 | 276 | ||
277 | if (((buf[1] >> 3) & 0x01) == 1) { | 277 | c->post_bit_error.len = 1; |
278 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | 278 | c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; |
279 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | 279 | c->post_bit_error.stat[0].uvalue = priv->post_bit_error; |
280 | } | 280 | } else { |
281 | c->post_bit_error.len = 1; | ||
282 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
281 | } | 283 | } |
282 | 284 | ||
283 | dev_dbg(&priv->i2c->dev, "%s: lock=%02x %02x\n", __func__, buf[0], | ||
284 | buf[1]); | ||
285 | |||
286 | return ret; | 285 | return ret; |
287 | error: | 286 | error: |
288 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 287 | dev_dbg(&client->dev, "failed=%d\n", ret); |
289 | return ret; | 288 | return ret; |
290 | } | 289 | } |
291 | 290 | ||
292 | int cxd2820r_init_c(struct dvb_frontend *fe) | 291 | int cxd2820r_init_c(struct dvb_frontend *fe) |
293 | { | 292 | { |
294 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 293 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
294 | struct i2c_client *client = priv->client[0]; | ||
295 | int ret; | 295 | int ret; |
296 | 296 | ||
297 | ret = cxd2820r_wr_reg(priv, 0x00085, 0x07); | 297 | dev_dbg(&client->dev, "\n"); |
298 | |||
299 | ret = regmap_write(priv->regmap[0], 0x0085, 0x07); | ||
298 | if (ret) | 300 | if (ret) |
299 | goto error; | 301 | goto error; |
300 | 302 | ||
301 | return ret; | 303 | return ret; |
302 | error: | 304 | error: |
303 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 305 | dev_dbg(&client->dev, "failed=%d\n", ret); |
304 | return ret; | 306 | return ret; |
305 | } | 307 | } |
306 | 308 | ||
307 | int cxd2820r_sleep_c(struct dvb_frontend *fe) | 309 | int cxd2820r_sleep_c(struct dvb_frontend *fe) |
308 | { | 310 | { |
309 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 311 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
310 | int ret, i; | 312 | struct i2c_client *client = priv->client[0]; |
313 | int ret; | ||
311 | struct reg_val_mask tab[] = { | 314 | struct reg_val_mask tab[] = { |
312 | { 0x000ff, 0x1f, 0xff }, | 315 | { 0x000ff, 0x1f, 0xff }, |
313 | { 0x00085, 0x00, 0xff }, | 316 | { 0x00085, 0x00, 0xff }, |
@@ -316,20 +319,17 @@ int cxd2820r_sleep_c(struct dvb_frontend *fe) | |||
316 | { 0x00080, 0x00, 0xff }, | 319 | { 0x00080, 0x00, 0xff }, |
317 | }; | 320 | }; |
318 | 321 | ||
319 | dev_dbg(&priv->i2c->dev, "%s\n", __func__); | 322 | dev_dbg(&client->dev, "\n"); |
320 | 323 | ||
321 | priv->delivery_system = SYS_UNDEFINED; | 324 | priv->delivery_system = SYS_UNDEFINED; |
322 | 325 | ||
323 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | 326 | ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab)); |
324 | ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val, | 327 | if (ret) |
325 | tab[i].mask); | 328 | goto error; |
326 | if (ret) | ||
327 | goto error; | ||
328 | } | ||
329 | 329 | ||
330 | return ret; | 330 | return ret; |
331 | error: | 331 | error: |
332 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 332 | dev_dbg(&client->dev, "failed=%d\n", ret); |
333 | return ret; | 333 | return ret; |
334 | } | 334 | } |
335 | 335 | ||
diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 314d3b8c1080..95267c6edb3a 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c | |||
@@ -21,178 +21,50 @@ | |||
21 | 21 | ||
22 | #include "cxd2820r_priv.h" | 22 | #include "cxd2820r_priv.h" |
23 | 23 | ||
24 | /* Max transfer size done by I2C transfer functions */ | 24 | /* Write register table */ |
25 | #define MAX_XFER_SIZE 64 | 25 | int cxd2820r_wr_reg_val_mask_tab(struct cxd2820r_priv *priv, |
26 | 26 | const struct reg_val_mask *tab, int tab_len) | |
27 | /* write multiple registers */ | ||
28 | static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg, | ||
29 | u8 *val, int len) | ||
30 | { | ||
31 | int ret; | ||
32 | u8 buf[MAX_XFER_SIZE]; | ||
33 | struct i2c_msg msg[1] = { | ||
34 | { | ||
35 | .addr = i2c, | ||
36 | .flags = 0, | ||
37 | .len = len + 1, | ||
38 | .buf = buf, | ||
39 | } | ||
40 | }; | ||
41 | |||
42 | if (1 + len > sizeof(buf)) { | ||
43 | dev_warn(&priv->i2c->dev, | ||
44 | "%s: i2c wr reg=%04x: len=%d is too big!\n", | ||
45 | KBUILD_MODNAME, reg, len); | ||
46 | return -EINVAL; | ||
47 | } | ||
48 | |||
49 | buf[0] = reg; | ||
50 | memcpy(&buf[1], val, len); | ||
51 | |||
52 | ret = i2c_transfer(priv->i2c, msg, 1); | ||
53 | if (ret == 1) { | ||
54 | ret = 0; | ||
55 | } else { | ||
56 | dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ | ||
57 | "len=%d\n", KBUILD_MODNAME, ret, reg, len); | ||
58 | ret = -EREMOTEIO; | ||
59 | } | ||
60 | return ret; | ||
61 | } | ||
62 | |||
63 | /* read multiple registers */ | ||
64 | static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg, | ||
65 | u8 *val, int len) | ||
66 | { | ||
67 | int ret; | ||
68 | u8 buf[MAX_XFER_SIZE]; | ||
69 | struct i2c_msg msg[2] = { | ||
70 | { | ||
71 | .addr = i2c, | ||
72 | .flags = 0, | ||
73 | .len = 1, | ||
74 | .buf = ®, | ||
75 | }, { | ||
76 | .addr = i2c, | ||
77 | .flags = I2C_M_RD, | ||
78 | .len = len, | ||
79 | .buf = buf, | ||
80 | } | ||
81 | }; | ||
82 | |||
83 | if (len > sizeof(buf)) { | ||
84 | dev_warn(&priv->i2c->dev, | ||
85 | "%s: i2c wr reg=%04x: len=%d is too big!\n", | ||
86 | KBUILD_MODNAME, reg, len); | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | |||
90 | ret = i2c_transfer(priv->i2c, msg, 2); | ||
91 | if (ret == 2) { | ||
92 | memcpy(val, buf, len); | ||
93 | ret = 0; | ||
94 | } else { | ||
95 | dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ | ||
96 | "len=%d\n", KBUILD_MODNAME, ret, reg, len); | ||
97 | ret = -EREMOTEIO; | ||
98 | } | ||
99 | |||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | /* write multiple registers */ | ||
104 | int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val, | ||
105 | int len) | ||
106 | { | 27 | { |
28 | struct i2c_client *client = priv->client[0]; | ||
107 | int ret; | 29 | int ret; |
108 | u8 i2c_addr; | 30 | unsigned int i, reg, mask, val; |
109 | u8 reg = (reginfo >> 0) & 0xff; | 31 | struct regmap *regmap; |
110 | u8 bank = (reginfo >> 8) & 0xff; | ||
111 | u8 i2c = (reginfo >> 16) & 0x01; | ||
112 | |||
113 | /* select I2C */ | ||
114 | if (i2c) | ||
115 | i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */ | ||
116 | else | ||
117 | i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */ | ||
118 | 32 | ||
119 | /* switch bank if needed */ | 33 | dev_dbg(&client->dev, "tab_len=%d\n", tab_len); |
120 | if (bank != priv->bank[i2c]) { | ||
121 | ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1); | ||
122 | if (ret) | ||
123 | return ret; | ||
124 | priv->bank[i2c] = bank; | ||
125 | } | ||
126 | return cxd2820r_wr_regs_i2c(priv, i2c_addr, reg, val, len); | ||
127 | } | ||
128 | |||
129 | /* read multiple registers */ | ||
130 | int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val, | ||
131 | int len) | ||
132 | { | ||
133 | int ret; | ||
134 | u8 i2c_addr; | ||
135 | u8 reg = (reginfo >> 0) & 0xff; | ||
136 | u8 bank = (reginfo >> 8) & 0xff; | ||
137 | u8 i2c = (reginfo >> 16) & 0x01; | ||
138 | |||
139 | /* select I2C */ | ||
140 | if (i2c) | ||
141 | i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */ | ||
142 | else | ||
143 | i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */ | ||
144 | 34 | ||
145 | /* switch bank if needed */ | 35 | for (i = 0; i < tab_len; i++) { |
146 | if (bank != priv->bank[i2c]) { | 36 | if ((tab[i].reg >> 16) & 0x1) |
147 | ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1); | 37 | regmap = priv->regmap[1]; |
148 | if (ret) | 38 | else |
149 | return ret; | 39 | regmap = priv->regmap[0]; |
150 | priv->bank[i2c] = bank; | ||
151 | } | ||
152 | return cxd2820r_rd_regs_i2c(priv, i2c_addr, reg, val, len); | ||
153 | } | ||
154 | |||
155 | /* write single register */ | ||
156 | int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val) | ||
157 | { | ||
158 | return cxd2820r_wr_regs(priv, reg, &val, 1); | ||
159 | } | ||
160 | |||
161 | /* read single register */ | ||
162 | int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val) | ||
163 | { | ||
164 | return cxd2820r_rd_regs(priv, reg, val, 1); | ||
165 | } | ||
166 | 40 | ||
167 | /* write single register with mask */ | 41 | reg = (tab[i].reg >> 0) & 0xffff; |
168 | int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val, | 42 | val = tab[i].val; |
169 | u8 mask) | 43 | mask = tab[i].mask; |
170 | { | ||
171 | int ret; | ||
172 | u8 tmp; | ||
173 | 44 | ||
174 | /* no need for read if whole reg is written */ | 45 | if (mask == 0xff) |
175 | if (mask != 0xff) { | 46 | ret = regmap_write(regmap, reg, val); |
176 | ret = cxd2820r_rd_reg(priv, reg, &tmp); | 47 | else |
48 | ret = regmap_write_bits(regmap, reg, mask, val); | ||
177 | if (ret) | 49 | if (ret) |
178 | return ret; | 50 | goto error; |
179 | |||
180 | val &= mask; | ||
181 | tmp &= ~mask; | ||
182 | val |= tmp; | ||
183 | } | 51 | } |
184 | 52 | ||
185 | return cxd2820r_wr_reg(priv, reg, val); | 53 | return 0; |
54 | error: | ||
55 | dev_dbg(&client->dev, "failed=%d\n", ret); | ||
56 | return ret; | ||
186 | } | 57 | } |
187 | 58 | ||
188 | int cxd2820r_gpio(struct dvb_frontend *fe, u8 *gpio) | 59 | int cxd2820r_gpio(struct dvb_frontend *fe, u8 *gpio) |
189 | { | 60 | { |
190 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 61 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
62 | struct i2c_client *client = priv->client[0]; | ||
63 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
191 | int ret, i; | 64 | int ret, i; |
192 | u8 tmp0, tmp1; | 65 | u8 tmp0, tmp1; |
193 | 66 | ||
194 | dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, | 67 | dev_dbg(&client->dev, "delivery_system=%d\n", c->delivery_system); |
195 | fe->dtv_property_cache.delivery_system); | ||
196 | 68 | ||
197 | /* update GPIOs only when needed */ | 69 | /* update GPIOs only when needed */ |
198 | if (!memcmp(gpio, priv->gpio, sizeof(priv->gpio))) | 70 | if (!memcmp(gpio, priv->gpio, sizeof(priv->gpio))) |
@@ -219,20 +91,18 @@ int cxd2820r_gpio(struct dvb_frontend *fe, u8 *gpio) | |||
219 | else | 91 | else |
220 | tmp1 |= (0 << (0 + i)); | 92 | tmp1 |= (0 << (0 + i)); |
221 | 93 | ||
222 | dev_dbg(&priv->i2c->dev, "%s: gpio i=%d %02x %02x\n", __func__, | 94 | dev_dbg(&client->dev, "gpio i=%d %02x %02x\n", i, tmp0, tmp1); |
223 | i, tmp0, tmp1); | ||
224 | } | 95 | } |
225 | 96 | ||
226 | dev_dbg(&priv->i2c->dev, "%s: wr gpio=%02x %02x\n", __func__, tmp0, | 97 | dev_dbg(&client->dev, "wr gpio=%02x %02x\n", tmp0, tmp1); |
227 | tmp1); | ||
228 | 98 | ||
229 | /* write bits [7:2] */ | 99 | /* write bits [7:2] */ |
230 | ret = cxd2820r_wr_reg_mask(priv, 0x00089, tmp0, 0xfc); | 100 | ret = regmap_update_bits(priv->regmap[0], 0x0089, 0xfc, tmp0); |
231 | if (ret) | 101 | if (ret) |
232 | goto error; | 102 | goto error; |
233 | 103 | ||
234 | /* write bits [5:0] */ | 104 | /* write bits [5:0] */ |
235 | ret = cxd2820r_wr_reg_mask(priv, 0x0008e, tmp1, 0x3f); | 105 | ret = regmap_update_bits(priv->regmap[0], 0x008e, 0x3f, tmp1); |
236 | if (ret) | 106 | if (ret) |
237 | goto error; | 107 | goto error; |
238 | 108 | ||
@@ -240,18 +110,18 @@ int cxd2820r_gpio(struct dvb_frontend *fe, u8 *gpio) | |||
240 | 110 | ||
241 | return ret; | 111 | return ret; |
242 | error: | 112 | error: |
243 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 113 | dev_dbg(&client->dev, "failed=%d\n", ret); |
244 | return ret; | 114 | return ret; |
245 | } | 115 | } |
246 | 116 | ||
247 | static int cxd2820r_set_frontend(struct dvb_frontend *fe) | 117 | static int cxd2820r_set_frontend(struct dvb_frontend *fe) |
248 | { | 118 | { |
249 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 119 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
120 | struct i2c_client *client = priv->client[0]; | ||
250 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 121 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
251 | int ret; | 122 | int ret; |
252 | 123 | ||
253 | dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, | 124 | dev_dbg(&client->dev, "delivery_system=%d\n", c->delivery_system); |
254 | fe->dtv_property_cache.delivery_system); | ||
255 | 125 | ||
256 | switch (c->delivery_system) { | 126 | switch (c->delivery_system) { |
257 | case SYS_DVBT: | 127 | case SYS_DVBT: |
@@ -279,8 +149,7 @@ static int cxd2820r_set_frontend(struct dvb_frontend *fe) | |||
279 | goto err; | 149 | goto err; |
280 | break; | 150 | break; |
281 | default: | 151 | default: |
282 | dev_dbg(&priv->i2c->dev, "%s: error state=%d\n", __func__, | 152 | dev_dbg(&client->dev, "invalid delivery_system\n"); |
283 | fe->dtv_property_cache.delivery_system); | ||
284 | ret = -EINVAL; | 153 | ret = -EINVAL; |
285 | break; | 154 | break; |
286 | } | 155 | } |
@@ -291,12 +160,13 @@ err: | |||
291 | static int cxd2820r_read_status(struct dvb_frontend *fe, enum fe_status *status) | 160 | static int cxd2820r_read_status(struct dvb_frontend *fe, enum fe_status *status) |
292 | { | 161 | { |
293 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 162 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
163 | struct i2c_client *client = priv->client[0]; | ||
164 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
294 | int ret; | 165 | int ret; |
295 | 166 | ||
296 | dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, | 167 | dev_dbg(&client->dev, "delivery_system=%d\n", c->delivery_system); |
297 | fe->dtv_property_cache.delivery_system); | ||
298 | 168 | ||
299 | switch (fe->dtv_property_cache.delivery_system) { | 169 | switch (c->delivery_system) { |
300 | case SYS_DVBT: | 170 | case SYS_DVBT: |
301 | ret = cxd2820r_read_status_t(fe, status); | 171 | ret = cxd2820r_read_status_t(fe, status); |
302 | break; | 172 | break; |
@@ -317,15 +187,16 @@ static int cxd2820r_get_frontend(struct dvb_frontend *fe, | |||
317 | struct dtv_frontend_properties *p) | 187 | struct dtv_frontend_properties *p) |
318 | { | 188 | { |
319 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 189 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
190 | struct i2c_client *client = priv->client[0]; | ||
191 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
320 | int ret; | 192 | int ret; |
321 | 193 | ||
322 | dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, | 194 | dev_dbg(&client->dev, "delivery_system=%d\n", c->delivery_system); |
323 | fe->dtv_property_cache.delivery_system); | ||
324 | 195 | ||
325 | if (priv->delivery_system == SYS_UNDEFINED) | 196 | if (priv->delivery_system == SYS_UNDEFINED) |
326 | return 0; | 197 | return 0; |
327 | 198 | ||
328 | switch (fe->dtv_property_cache.delivery_system) { | 199 | switch (c->delivery_system) { |
329 | case SYS_DVBT: | 200 | case SYS_DVBT: |
330 | ret = cxd2820r_get_frontend_t(fe, p); | 201 | ret = cxd2820r_get_frontend_t(fe, p); |
331 | break; | 202 | break; |
@@ -345,101 +216,60 @@ static int cxd2820r_get_frontend(struct dvb_frontend *fe, | |||
345 | static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber) | 216 | static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber) |
346 | { | 217 | { |
347 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 218 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
348 | int ret; | 219 | struct i2c_client *client = priv->client[0]; |
220 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
349 | 221 | ||
350 | dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, | 222 | dev_dbg(&client->dev, "delivery_system=%d\n", c->delivery_system); |
351 | fe->dtv_property_cache.delivery_system); | ||
352 | 223 | ||
353 | switch (fe->dtv_property_cache.delivery_system) { | 224 | *ber = (priv->post_bit_error - priv->post_bit_error_prev_dvbv3); |
354 | case SYS_DVBT: | 225 | priv->post_bit_error_prev_dvbv3 = priv->post_bit_error; |
355 | ret = cxd2820r_read_ber_t(fe, ber); | 226 | |
356 | break; | 227 | return 0; |
357 | case SYS_DVBT2: | ||
358 | ret = cxd2820r_read_ber_t2(fe, ber); | ||
359 | break; | ||
360 | case SYS_DVBC_ANNEX_A: | ||
361 | ret = cxd2820r_read_ber_c(fe, ber); | ||
362 | break; | ||
363 | default: | ||
364 | ret = -EINVAL; | ||
365 | break; | ||
366 | } | ||
367 | return ret; | ||
368 | } | 228 | } |
369 | 229 | ||
370 | static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | 230 | static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength) |
371 | { | 231 | { |
372 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 232 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
373 | int ret; | 233 | struct i2c_client *client = priv->client[0]; |
234 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
374 | 235 | ||
375 | dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, | 236 | dev_dbg(&client->dev, "delivery_system=%d\n", c->delivery_system); |
376 | fe->dtv_property_cache.delivery_system); | ||
377 | 237 | ||
378 | switch (fe->dtv_property_cache.delivery_system) { | 238 | if (c->strength.stat[0].scale == FE_SCALE_RELATIVE) |
379 | case SYS_DVBT: | 239 | *strength = c->strength.stat[0].uvalue; |
380 | ret = cxd2820r_read_signal_strength_t(fe, strength); | 240 | else |
381 | break; | 241 | *strength = 0; |
382 | case SYS_DVBT2: | 242 | |
383 | ret = cxd2820r_read_signal_strength_t2(fe, strength); | 243 | return 0; |
384 | break; | ||
385 | case SYS_DVBC_ANNEX_A: | ||
386 | ret = cxd2820r_read_signal_strength_c(fe, strength); | ||
387 | break; | ||
388 | default: | ||
389 | ret = -EINVAL; | ||
390 | break; | ||
391 | } | ||
392 | return ret; | ||
393 | } | 244 | } |
394 | 245 | ||
395 | static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr) | 246 | static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr) |
396 | { | 247 | { |
397 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 248 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
398 | int ret; | 249 | struct i2c_client *client = priv->client[0]; |
250 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
399 | 251 | ||
400 | dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, | 252 | dev_dbg(&client->dev, "delivery_system=%d\n", c->delivery_system); |
401 | fe->dtv_property_cache.delivery_system); | ||
402 | 253 | ||
403 | switch (fe->dtv_property_cache.delivery_system) { | 254 | if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) |
404 | case SYS_DVBT: | 255 | *snr = div_s64(c->cnr.stat[0].svalue, 100); |
405 | ret = cxd2820r_read_snr_t(fe, snr); | 256 | else |
406 | break; | 257 | *snr = 0; |
407 | case SYS_DVBT2: | 258 | |
408 | ret = cxd2820r_read_snr_t2(fe, snr); | 259 | return 0; |
409 | break; | ||
410 | case SYS_DVBC_ANNEX_A: | ||
411 | ret = cxd2820r_read_snr_c(fe, snr); | ||
412 | break; | ||
413 | default: | ||
414 | ret = -EINVAL; | ||
415 | break; | ||
416 | } | ||
417 | return ret; | ||
418 | } | 260 | } |
419 | 261 | ||
420 | static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | 262 | static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) |
421 | { | 263 | { |
422 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 264 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
423 | int ret; | 265 | struct i2c_client *client = priv->client[0]; |
266 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
424 | 267 | ||
425 | dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, | 268 | dev_dbg(&client->dev, "delivery_system=%d\n", c->delivery_system); |
426 | fe->dtv_property_cache.delivery_system); | ||
427 | 269 | ||
428 | switch (fe->dtv_property_cache.delivery_system) { | 270 | *ucblocks = 0; |
429 | case SYS_DVBT: | 271 | |
430 | ret = cxd2820r_read_ucblocks_t(fe, ucblocks); | 272 | return 0; |
431 | break; | ||
432 | case SYS_DVBT2: | ||
433 | ret = cxd2820r_read_ucblocks_t2(fe, ucblocks); | ||
434 | break; | ||
435 | case SYS_DVBC_ANNEX_A: | ||
436 | ret = cxd2820r_read_ucblocks_c(fe, ucblocks); | ||
437 | break; | ||
438 | default: | ||
439 | ret = -EINVAL; | ||
440 | break; | ||
441 | } | ||
442 | return ret; | ||
443 | } | 273 | } |
444 | 274 | ||
445 | static int cxd2820r_init(struct dvb_frontend *fe) | 275 | static int cxd2820r_init(struct dvb_frontend *fe) |
@@ -450,12 +280,13 @@ static int cxd2820r_init(struct dvb_frontend *fe) | |||
450 | static int cxd2820r_sleep(struct dvb_frontend *fe) | 280 | static int cxd2820r_sleep(struct dvb_frontend *fe) |
451 | { | 281 | { |
452 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 282 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
283 | struct i2c_client *client = priv->client[0]; | ||
284 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
453 | int ret; | 285 | int ret; |
454 | 286 | ||
455 | dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, | 287 | dev_dbg(&client->dev, "delivery_system=%d\n", c->delivery_system); |
456 | fe->dtv_property_cache.delivery_system); | ||
457 | 288 | ||
458 | switch (fe->dtv_property_cache.delivery_system) { | 289 | switch (c->delivery_system) { |
459 | case SYS_DVBT: | 290 | case SYS_DVBT: |
460 | ret = cxd2820r_sleep_t(fe); | 291 | ret = cxd2820r_sleep_t(fe); |
461 | break; | 292 | break; |
@@ -476,12 +307,13 @@ static int cxd2820r_get_tune_settings(struct dvb_frontend *fe, | |||
476 | struct dvb_frontend_tune_settings *s) | 307 | struct dvb_frontend_tune_settings *s) |
477 | { | 308 | { |
478 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 309 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
310 | struct i2c_client *client = priv->client[0]; | ||
311 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
479 | int ret; | 312 | int ret; |
480 | 313 | ||
481 | dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, | 314 | dev_dbg(&client->dev, "delivery_system=%d\n", c->delivery_system); |
482 | fe->dtv_property_cache.delivery_system); | ||
483 | 315 | ||
484 | switch (fe->dtv_property_cache.delivery_system) { | 316 | switch (c->delivery_system) { |
485 | case SYS_DVBT: | 317 | case SYS_DVBT: |
486 | ret = cxd2820r_get_tune_settings_t(fe, s); | 318 | ret = cxd2820r_get_tune_settings_t(fe, s); |
487 | break; | 319 | break; |
@@ -501,12 +333,12 @@ static int cxd2820r_get_tune_settings(struct dvb_frontend *fe, | |||
501 | static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe) | 333 | static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe) |
502 | { | 334 | { |
503 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 335 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
336 | struct i2c_client *client = priv->client[0]; | ||
504 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 337 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
505 | int ret, i; | 338 | int ret, i; |
506 | enum fe_status status = 0; | 339 | enum fe_status status = 0; |
507 | 340 | ||
508 | dev_dbg(&priv->i2c->dev, "%s: delsys=%d\n", __func__, | 341 | dev_dbg(&client->dev, "delivery_system=%d\n", c->delivery_system); |
509 | fe->dtv_property_cache.delivery_system); | ||
510 | 342 | ||
511 | /* switch between DVB-T and DVB-T2 when tune fails */ | 343 | /* switch between DVB-T and DVB-T2 when tune fails */ |
512 | if (priv->last_tune_failed) { | 344 | if (priv->last_tune_failed) { |
@@ -530,7 +362,6 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe) | |||
530 | if (ret) | 362 | if (ret) |
531 | goto error; | 363 | goto error; |
532 | 364 | ||
533 | |||
534 | /* frontend lock wait loop count */ | 365 | /* frontend lock wait loop count */ |
535 | switch (priv->delivery_system) { | 366 | switch (priv->delivery_system) { |
536 | case SYS_DVBT: | 367 | case SYS_DVBT: |
@@ -548,7 +379,7 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe) | |||
548 | 379 | ||
549 | /* wait frontend lock */ | 380 | /* wait frontend lock */ |
550 | for (; i > 0; i--) { | 381 | for (; i > 0; i--) { |
551 | dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i); | 382 | dev_dbg(&client->dev, "loop=%d\n", i); |
552 | msleep(50); | 383 | msleep(50); |
553 | ret = cxd2820r_read_status(fe, &status); | 384 | ret = cxd2820r_read_status(fe, &status); |
554 | if (ret) | 385 | if (ret) |
@@ -568,7 +399,7 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe) | |||
568 | } | 399 | } |
569 | 400 | ||
570 | error: | 401 | error: |
571 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 402 | dev_dbg(&client->dev, "failed=%d\n", ret); |
572 | return DVBFE_ALGO_SEARCH_ERROR; | 403 | return DVBFE_ALGO_SEARCH_ERROR; |
573 | } | 404 | } |
574 | 405 | ||
@@ -580,27 +411,23 @@ static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe) | |||
580 | static void cxd2820r_release(struct dvb_frontend *fe) | 411 | static void cxd2820r_release(struct dvb_frontend *fe) |
581 | { | 412 | { |
582 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 413 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
414 | struct i2c_client *client = priv->client[0]; | ||
583 | 415 | ||
584 | dev_dbg(&priv->i2c->dev, "%s\n", __func__); | 416 | dev_dbg(&client->dev, "\n"); |
585 | 417 | ||
586 | #ifdef CONFIG_GPIOLIB | 418 | i2c_unregister_device(client); |
587 | /* remove GPIOs */ | ||
588 | if (priv->gpio_chip.label) | ||
589 | gpiochip_remove(&priv->gpio_chip); | ||
590 | 419 | ||
591 | #endif | ||
592 | kfree(priv); | ||
593 | return; | 420 | return; |
594 | } | 421 | } |
595 | 422 | ||
596 | static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) | 423 | static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) |
597 | { | 424 | { |
598 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 425 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
426 | struct i2c_client *client = priv->client[0]; | ||
599 | 427 | ||
600 | dev_dbg(&priv->i2c->dev, "%s: %d\n", __func__, enable); | 428 | dev_dbg_ratelimited(&client->dev, "enable=%d\n", enable); |
601 | 429 | ||
602 | /* Bit 0 of reg 0xdb in bank 0x00 controls I2C repeater */ | 430 | return regmap_update_bits(priv->regmap[0], 0x00db, 0x01, enable ? 1 : 0); |
603 | return cxd2820r_wr_reg_mask(priv, 0xdb, enable ? 1 : 0, 0x1); | ||
604 | } | 431 | } |
605 | 432 | ||
606 | #ifdef CONFIG_GPIOLIB | 433 | #ifdef CONFIG_GPIOLIB |
@@ -608,9 +435,10 @@ static int cxd2820r_gpio_direction_output(struct gpio_chip *chip, unsigned nr, | |||
608 | int val) | 435 | int val) |
609 | { | 436 | { |
610 | struct cxd2820r_priv *priv = gpiochip_get_data(chip); | 437 | struct cxd2820r_priv *priv = gpiochip_get_data(chip); |
438 | struct i2c_client *client = priv->client[0]; | ||
611 | u8 gpio[GPIO_COUNT]; | 439 | u8 gpio[GPIO_COUNT]; |
612 | 440 | ||
613 | dev_dbg(&priv->i2c->dev, "%s: nr=%d val=%d\n", __func__, nr, val); | 441 | dev_dbg(&client->dev, "nr=%u val=%d\n", nr, val); |
614 | 442 | ||
615 | memcpy(gpio, priv->gpio, sizeof(gpio)); | 443 | memcpy(gpio, priv->gpio, sizeof(gpio)); |
616 | gpio[nr] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | (val << 2); | 444 | gpio[nr] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | (val << 2); |
@@ -621,9 +449,10 @@ static int cxd2820r_gpio_direction_output(struct gpio_chip *chip, unsigned nr, | |||
621 | static void cxd2820r_gpio_set(struct gpio_chip *chip, unsigned nr, int val) | 449 | static void cxd2820r_gpio_set(struct gpio_chip *chip, unsigned nr, int val) |
622 | { | 450 | { |
623 | struct cxd2820r_priv *priv = gpiochip_get_data(chip); | 451 | struct cxd2820r_priv *priv = gpiochip_get_data(chip); |
452 | struct i2c_client *client = priv->client[0]; | ||
624 | u8 gpio[GPIO_COUNT]; | 453 | u8 gpio[GPIO_COUNT]; |
625 | 454 | ||
626 | dev_dbg(&priv->i2c->dev, "%s: nr=%d val=%d\n", __func__, nr, val); | 455 | dev_dbg(&client->dev, "nr=%u val=%d\n", nr, val); |
627 | 456 | ||
628 | memcpy(gpio, priv->gpio, sizeof(gpio)); | 457 | memcpy(gpio, priv->gpio, sizeof(gpio)); |
629 | gpio[nr] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | (val << 2); | 458 | gpio[nr] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | (val << 2); |
@@ -636,8 +465,9 @@ static void cxd2820r_gpio_set(struct gpio_chip *chip, unsigned nr, int val) | |||
636 | static int cxd2820r_gpio_get(struct gpio_chip *chip, unsigned nr) | 465 | static int cxd2820r_gpio_get(struct gpio_chip *chip, unsigned nr) |
637 | { | 466 | { |
638 | struct cxd2820r_priv *priv = gpiochip_get_data(chip); | 467 | struct cxd2820r_priv *priv = gpiochip_get_data(chip); |
468 | struct i2c_client *client = priv->client[0]; | ||
639 | 469 | ||
640 | dev_dbg(&priv->i2c->dev, "%s: nr=%d\n", __func__, nr); | 470 | dev_dbg(&client->dev, "nr=%u\n", nr); |
641 | 471 | ||
642 | return (priv->gpio[nr] >> 2) & 0x01; | 472 | return (priv->gpio[nr] >> 2) & 0x01; |
643 | } | 473 | } |
@@ -689,52 +519,163 @@ static const struct dvb_frontend_ops cxd2820r_ops = { | |||
689 | .read_signal_strength = cxd2820r_read_signal_strength, | 519 | .read_signal_strength = cxd2820r_read_signal_strength, |
690 | }; | 520 | }; |
691 | 521 | ||
692 | struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, | 522 | /* |
693 | struct i2c_adapter *i2c, int *gpio_chip_base | 523 | * XXX: That is wrapper to cxd2820r_probe() via driver core in order to provide |
694 | ) | 524 | * proper I2C client for legacy media attach binding. |
525 | * New users must use I2C client binding directly! | ||
526 | */ | ||
527 | struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *config, | ||
528 | struct i2c_adapter *adapter, | ||
529 | int *gpio_chip_base) | ||
530 | { | ||
531 | struct i2c_client *client; | ||
532 | struct i2c_board_info board_info; | ||
533 | struct cxd2820r_platform_data pdata; | ||
534 | |||
535 | pdata.ts_mode = config->ts_mode; | ||
536 | pdata.ts_clk_inv = config->ts_clock_inv; | ||
537 | pdata.if_agc_polarity = config->if_agc_polarity; | ||
538 | pdata.spec_inv = config->spec_inv; | ||
539 | pdata.gpio_chip_base = &gpio_chip_base; | ||
540 | pdata.attach_in_use = true; | ||
541 | |||
542 | memset(&board_info, 0, sizeof(board_info)); | ||
543 | strlcpy(board_info.type, "cxd2820r", I2C_NAME_SIZE); | ||
544 | board_info.addr = config->i2c_address; | ||
545 | board_info.platform_data = &pdata; | ||
546 | client = i2c_new_device(adapter, &board_info); | ||
547 | if (!client || !client->dev.driver) | ||
548 | return NULL; | ||
549 | |||
550 | return pdata.get_dvb_frontend(client); | ||
551 | } | ||
552 | EXPORT_SYMBOL(cxd2820r_attach); | ||
553 | |||
554 | static struct dvb_frontend *cxd2820r_get_dvb_frontend(struct i2c_client *client) | ||
555 | { | ||
556 | struct cxd2820r_priv *priv = i2c_get_clientdata(client); | ||
557 | |||
558 | dev_dbg(&client->dev, "\n"); | ||
559 | |||
560 | return &priv->fe; | ||
561 | } | ||
562 | |||
563 | static int cxd2820r_probe(struct i2c_client *client, | ||
564 | const struct i2c_device_id *id) | ||
695 | { | 565 | { |
566 | struct cxd2820r_platform_data *pdata = client->dev.platform_data; | ||
696 | struct cxd2820r_priv *priv; | 567 | struct cxd2820r_priv *priv; |
697 | int ret; | 568 | int ret, *gpio_chip_base; |
698 | u8 tmp; | 569 | unsigned int utmp; |
570 | static const struct regmap_range_cfg regmap_range_cfg0[] = { | ||
571 | { | ||
572 | .range_min = 0x0000, | ||
573 | .range_max = 0x3fff, | ||
574 | .selector_reg = 0x00, | ||
575 | .selector_mask = 0xff, | ||
576 | .selector_shift = 0, | ||
577 | .window_start = 0x00, | ||
578 | .window_len = 0x100, | ||
579 | }, | ||
580 | }; | ||
581 | static const struct regmap_range_cfg regmap_range_cfg1[] = { | ||
582 | { | ||
583 | .range_min = 0x0000, | ||
584 | .range_max = 0x01ff, | ||
585 | .selector_reg = 0x00, | ||
586 | .selector_mask = 0xff, | ||
587 | .selector_shift = 0, | ||
588 | .window_start = 0x00, | ||
589 | .window_len = 0x100, | ||
590 | }, | ||
591 | }; | ||
592 | static const struct regmap_config regmap_config0 = { | ||
593 | .reg_bits = 8, | ||
594 | .val_bits = 8, | ||
595 | .max_register = 0x3fff, | ||
596 | .ranges = regmap_range_cfg0, | ||
597 | .num_ranges = ARRAY_SIZE(regmap_range_cfg0), | ||
598 | .cache_type = REGCACHE_NONE, | ||
599 | }; | ||
600 | static const struct regmap_config regmap_config1 = { | ||
601 | .reg_bits = 8, | ||
602 | .val_bits = 8, | ||
603 | .max_register = 0x01ff, | ||
604 | .ranges = regmap_range_cfg1, | ||
605 | .num_ranges = ARRAY_SIZE(regmap_range_cfg1), | ||
606 | .cache_type = REGCACHE_NONE, | ||
607 | }; | ||
608 | |||
609 | dev_dbg(&client->dev, "\n"); | ||
699 | 610 | ||
700 | priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL); | 611 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
701 | if (!priv) { | 612 | if (!priv) { |
702 | ret = -ENOMEM; | 613 | ret = -ENOMEM; |
703 | dev_err(&i2c->dev, "%s: kzalloc() failed\n", | 614 | goto err; |
704 | KBUILD_MODNAME); | ||
705 | goto error; | ||
706 | } | 615 | } |
707 | 616 | ||
708 | priv->i2c = i2c; | 617 | priv->client[0] = client; |
709 | memcpy(&priv->cfg, cfg, sizeof(struct cxd2820r_config)); | 618 | priv->i2c = client->adapter; |
710 | memcpy(&priv->fe.ops, &cxd2820r_ops, sizeof(struct dvb_frontend_ops)); | 619 | priv->ts_mode = pdata->ts_mode; |
711 | priv->fe.demodulator_priv = priv; | 620 | priv->ts_clk_inv = pdata->ts_clk_inv; |
621 | priv->if_agc_polarity = pdata->if_agc_polarity; | ||
622 | priv->spec_inv = pdata->spec_inv; | ||
623 | gpio_chip_base = *pdata->gpio_chip_base; | ||
624 | priv->regmap[0] = regmap_init_i2c(priv->client[0], ®map_config0); | ||
625 | if (IS_ERR(priv->regmap[0])) { | ||
626 | ret = PTR_ERR(priv->regmap[0]); | ||
627 | goto err_kfree; | ||
628 | } | ||
712 | 629 | ||
713 | priv->bank[0] = priv->bank[1] = 0xff; | 630 | /* Check demod answers with correct chip id */ |
714 | ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp); | 631 | ret = regmap_read(priv->regmap[0], 0x00fd, &utmp); |
715 | dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, tmp); | 632 | if (ret) |
716 | if (ret || tmp != 0xe1) | 633 | goto err_regmap_0_regmap_exit; |
717 | goto error; | 634 | |
635 | dev_dbg(&client->dev, "chip_id=%02x\n", utmp); | ||
636 | |||
637 | if (utmp != 0xe1) { | ||
638 | ret = -ENODEV; | ||
639 | goto err_regmap_0_regmap_exit; | ||
640 | } | ||
641 | |||
642 | /* | ||
643 | * Chip has two I2C addresses for different register banks. We register | ||
644 | * one dummy I2C client in in order to get own I2C client for each | ||
645 | * register bank. | ||
646 | */ | ||
647 | priv->client[1] = i2c_new_dummy(client->adapter, client->addr | (1 << 1)); | ||
648 | if (!priv->client[1]) { | ||
649 | ret = -ENODEV; | ||
650 | dev_err(&client->dev, "I2C registration failed\n"); | ||
651 | if (ret) | ||
652 | goto err_regmap_0_regmap_exit; | ||
653 | } | ||
654 | |||
655 | priv->regmap[1] = regmap_init_i2c(priv->client[1], ®map_config1); | ||
656 | if (IS_ERR(priv->regmap[1])) { | ||
657 | ret = PTR_ERR(priv->regmap[1]); | ||
658 | goto err_client_1_i2c_unregister_device; | ||
659 | } | ||
718 | 660 | ||
719 | if (gpio_chip_base) { | 661 | if (gpio_chip_base) { |
720 | #ifdef CONFIG_GPIOLIB | 662 | #ifdef CONFIG_GPIOLIB |
721 | /* add GPIOs */ | 663 | /* Add GPIOs */ |
722 | priv->gpio_chip.label = KBUILD_MODNAME; | 664 | priv->gpio_chip.label = KBUILD_MODNAME; |
723 | priv->gpio_chip.parent = &priv->i2c->dev; | 665 | priv->gpio_chip.parent = &client->dev; |
724 | priv->gpio_chip.owner = THIS_MODULE; | 666 | priv->gpio_chip.owner = THIS_MODULE; |
725 | priv->gpio_chip.direction_output = | 667 | priv->gpio_chip.direction_output = cxd2820r_gpio_direction_output; |
726 | cxd2820r_gpio_direction_output; | ||
727 | priv->gpio_chip.set = cxd2820r_gpio_set; | 668 | priv->gpio_chip.set = cxd2820r_gpio_set; |
728 | priv->gpio_chip.get = cxd2820r_gpio_get; | 669 | priv->gpio_chip.get = cxd2820r_gpio_get; |
729 | priv->gpio_chip.base = -1; /* dynamic allocation */ | 670 | priv->gpio_chip.base = -1; /* Dynamic allocation */ |
730 | priv->gpio_chip.ngpio = GPIO_COUNT; | 671 | priv->gpio_chip.ngpio = GPIO_COUNT; |
731 | priv->gpio_chip.can_sleep = 1; | 672 | priv->gpio_chip.can_sleep = 1; |
732 | ret = gpiochip_add_data(&priv->gpio_chip, priv); | 673 | ret = gpiochip_add_data(&priv->gpio_chip, priv); |
733 | if (ret) | 674 | if (ret) |
734 | goto error; | 675 | goto err_regmap_1_regmap_exit; |
735 | 676 | ||
736 | dev_dbg(&priv->i2c->dev, "%s: gpio_chip.base=%d\n", __func__, | 677 | dev_dbg(&client->dev, "gpio_chip.base=%d\n", |
737 | priv->gpio_chip.base); | 678 | priv->gpio_chip.base); |
738 | 679 | ||
739 | *gpio_chip_base = priv->gpio_chip.base; | 680 | *gpio_chip_base = priv->gpio_chip.base; |
740 | #else | 681 | #else |
@@ -748,17 +689,73 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, | |||
748 | gpio[2] = 0; | 689 | gpio[2] = 0; |
749 | ret = cxd2820r_gpio(&priv->fe, gpio); | 690 | ret = cxd2820r_gpio(&priv->fe, gpio); |
750 | if (ret) | 691 | if (ret) |
751 | goto error; | 692 | goto err_regmap_1_regmap_exit; |
752 | #endif | 693 | #endif |
753 | } | 694 | } |
754 | 695 | ||
755 | return &priv->fe; | 696 | /* Create dvb frontend */ |
756 | error: | 697 | memcpy(&priv->fe.ops, &cxd2820r_ops, sizeof(priv->fe.ops)); |
757 | dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); | 698 | if (!pdata->attach_in_use) |
699 | priv->fe.ops.release = NULL; | ||
700 | priv->fe.demodulator_priv = priv; | ||
701 | i2c_set_clientdata(client, priv); | ||
702 | |||
703 | /* Setup callbacks */ | ||
704 | pdata->get_dvb_frontend = cxd2820r_get_dvb_frontend; | ||
705 | |||
706 | dev_info(&client->dev, "Sony CXD2820R successfully identified\n"); | ||
707 | |||
708 | return 0; | ||
709 | err_regmap_1_regmap_exit: | ||
710 | regmap_exit(priv->regmap[1]); | ||
711 | err_client_1_i2c_unregister_device: | ||
712 | i2c_unregister_device(priv->client[1]); | ||
713 | err_regmap_0_regmap_exit: | ||
714 | regmap_exit(priv->regmap[0]); | ||
715 | err_kfree: | ||
758 | kfree(priv); | 716 | kfree(priv); |
759 | return NULL; | 717 | err: |
718 | dev_dbg(&client->dev, "failed=%d\n", ret); | ||
719 | return ret; | ||
760 | } | 720 | } |
761 | EXPORT_SYMBOL(cxd2820r_attach); | 721 | |
722 | static int cxd2820r_remove(struct i2c_client *client) | ||
723 | { | ||
724 | struct cxd2820r_priv *priv = i2c_get_clientdata(client); | ||
725 | |||
726 | dev_dbg(&client->dev, "\n"); | ||
727 | |||
728 | #ifdef CONFIG_GPIOLIB | ||
729 | if (priv->gpio_chip.label) | ||
730 | gpiochip_remove(&priv->gpio_chip); | ||
731 | #endif | ||
732 | regmap_exit(priv->regmap[1]); | ||
733 | i2c_unregister_device(priv->client[1]); | ||
734 | |||
735 | regmap_exit(priv->regmap[0]); | ||
736 | |||
737 | kfree(priv); | ||
738 | |||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | static const struct i2c_device_id cxd2820r_id_table[] = { | ||
743 | {"cxd2820r", 0}, | ||
744 | {} | ||
745 | }; | ||
746 | MODULE_DEVICE_TABLE(i2c, cxd2820r_id_table); | ||
747 | |||
748 | static struct i2c_driver cxd2820r_driver = { | ||
749 | .driver = { | ||
750 | .name = "cxd2820r", | ||
751 | .suppress_bind_attrs = true, | ||
752 | }, | ||
753 | .probe = cxd2820r_probe, | ||
754 | .remove = cxd2820r_remove, | ||
755 | .id_table = cxd2820r_id_table, | ||
756 | }; | ||
757 | |||
758 | module_i2c_driver(cxd2820r_driver); | ||
762 | 759 | ||
763 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | 760 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); |
764 | MODULE_DESCRIPTION("Sony CXD2820R demodulator driver"); | 761 | MODULE_DESCRIPTION("Sony CXD2820R demodulator driver"); |
diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h index e31c48e53097..0d096206ac66 100644 --- a/drivers/media/dvb-frontends/cxd2820r_priv.h +++ b/drivers/media/dvb-frontends/cxd2820r_priv.h | |||
@@ -27,6 +27,8 @@ | |||
27 | #include "dvb_math.h" | 27 | #include "dvb_math.h" |
28 | #include "cxd2820r.h" | 28 | #include "cxd2820r.h" |
29 | #include <linux/gpio.h> | 29 | #include <linux/gpio.h> |
30 | #include <linux/math64.h> | ||
31 | #include <linux/regmap.h> | ||
30 | 32 | ||
31 | struct reg_val_mask { | 33 | struct reg_val_mask { |
32 | u32 reg; | 34 | u32 reg; |
@@ -34,14 +36,23 @@ struct reg_val_mask { | |||
34 | u8 mask; | 36 | u8 mask; |
35 | }; | 37 | }; |
36 | 38 | ||
39 | #define CXD2820R_CLK 41000000 | ||
40 | |||
37 | struct cxd2820r_priv { | 41 | struct cxd2820r_priv { |
42 | struct i2c_client *client[2]; | ||
43 | struct regmap *regmap[2]; | ||
38 | struct i2c_adapter *i2c; | 44 | struct i2c_adapter *i2c; |
39 | struct dvb_frontend fe; | 45 | struct dvb_frontend fe; |
40 | struct cxd2820r_config cfg; | 46 | u8 ts_mode; |
47 | bool ts_clk_inv; | ||
48 | bool if_agc_polarity; | ||
49 | bool spec_inv; | ||
50 | |||
51 | u64 post_bit_error_prev_dvbv3; | ||
52 | u64 post_bit_error; | ||
41 | 53 | ||
42 | bool ber_running; | 54 | bool ber_running; |
43 | 55 | ||
44 | u8 bank[2]; | ||
45 | #define GPIO_COUNT 3 | 56 | #define GPIO_COUNT 3 |
46 | u8 gpio[GPIO_COUNT]; | 57 | u8 gpio[GPIO_COUNT]; |
47 | #ifdef CONFIG_GPIOLIB | 58 | #ifdef CONFIG_GPIOLIB |
@@ -58,6 +69,9 @@ extern int cxd2820r_debug; | |||
58 | 69 | ||
59 | int cxd2820r_gpio(struct dvb_frontend *fe, u8 *gpio); | 70 | int cxd2820r_gpio(struct dvb_frontend *fe, u8 *gpio); |
60 | 71 | ||
72 | int cxd2820r_wr_reg_val_mask_tab(struct cxd2820r_priv *priv, | ||
73 | const struct reg_val_mask *tab, int tab_len); | ||
74 | |||
61 | int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val, | 75 | int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val, |
62 | u8 mask); | 76 | u8 mask); |
63 | 77 | ||
@@ -83,14 +97,6 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe); | |||
83 | 97 | ||
84 | int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status); | 98 | int cxd2820r_read_status_c(struct dvb_frontend *fe, enum fe_status *status); |
85 | 99 | ||
86 | int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber); | ||
87 | |||
88 | int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe, u16 *strength); | ||
89 | |||
90 | int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr); | ||
91 | |||
92 | int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks); | ||
93 | |||
94 | int cxd2820r_init_c(struct dvb_frontend *fe); | 100 | int cxd2820r_init_c(struct dvb_frontend *fe); |
95 | 101 | ||
96 | int cxd2820r_sleep_c(struct dvb_frontend *fe); | 102 | int cxd2820r_sleep_c(struct dvb_frontend *fe); |
@@ -107,14 +113,6 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe); | |||
107 | 113 | ||
108 | int cxd2820r_read_status_t(struct dvb_frontend *fe, enum fe_status *status); | 114 | int cxd2820r_read_status_t(struct dvb_frontend *fe, enum fe_status *status); |
109 | 115 | ||
110 | int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber); | ||
111 | |||
112 | int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe, u16 *strength); | ||
113 | |||
114 | int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr); | ||
115 | |||
116 | int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks); | ||
117 | |||
118 | int cxd2820r_init_t(struct dvb_frontend *fe); | 116 | int cxd2820r_init_t(struct dvb_frontend *fe); |
119 | 117 | ||
120 | int cxd2820r_sleep_t(struct dvb_frontend *fe); | 118 | int cxd2820r_sleep_t(struct dvb_frontend *fe); |
@@ -131,14 +129,6 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe); | |||
131 | 129 | ||
132 | int cxd2820r_read_status_t2(struct dvb_frontend *fe, enum fe_status *status); | 130 | int cxd2820r_read_status_t2(struct dvb_frontend *fe, enum fe_status *status); |
133 | 131 | ||
134 | int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber); | ||
135 | |||
136 | int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe, u16 *strength); | ||
137 | |||
138 | int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr); | ||
139 | |||
140 | int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks); | ||
141 | |||
142 | int cxd2820r_init_t2(struct dvb_frontend *fe); | 132 | int cxd2820r_init_t2(struct dvb_frontend *fe); |
143 | 133 | ||
144 | int cxd2820r_sleep_t2(struct dvb_frontend *fe); | 134 | int cxd2820r_sleep_t2(struct dvb_frontend *fe); |
diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c index 75ce7d8ded00..c2e7caf9b010 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t.c +++ b/drivers/media/dvb-frontends/cxd2820r_t.c | |||
@@ -24,10 +24,11 @@ | |||
24 | int cxd2820r_set_frontend_t(struct dvb_frontend *fe) | 24 | int cxd2820r_set_frontend_t(struct dvb_frontend *fe) |
25 | { | 25 | { |
26 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 26 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
27 | struct i2c_client *client = priv->client[0]; | ||
27 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 28 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
28 | int ret, i, bw_i; | 29 | int ret, bw_i; |
29 | u32 if_freq, if_ctl; | 30 | unsigned int utmp; |
30 | u64 num; | 31 | u32 if_frequency; |
31 | u8 buf[3], bw_param; | 32 | u8 buf[3], bw_param; |
32 | u8 bw_params1[][5] = { | 33 | u8 bw_params1[][5] = { |
33 | { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */ | 34 | { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */ |
@@ -45,9 +46,9 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe) | |||
45 | { 0x00085, 0x07, 0xff }, | 46 | { 0x00085, 0x07, 0xff }, |
46 | { 0x00088, 0x01, 0xff }, | 47 | { 0x00088, 0x01, 0xff }, |
47 | 48 | ||
48 | { 0x00070, priv->cfg.ts_mode, 0xff }, | 49 | { 0x00070, priv->ts_mode, 0xff }, |
49 | { 0x00071, !priv->cfg.ts_clock_inv << 4, 0x10 }, | 50 | { 0x00071, !priv->ts_clk_inv << 4, 0x10 }, |
50 | { 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 }, | 51 | { 0x000cb, priv->if_agc_polarity << 6, 0x40 }, |
51 | { 0x000a5, 0x00, 0x01 }, | 52 | { 0x000a5, 0x00, 0x01 }, |
52 | { 0x00082, 0x20, 0x60 }, | 53 | { 0x00082, 0x20, 0x60 }, |
53 | { 0x000c2, 0xc3, 0xff }, | 54 | { 0x000c2, 0xc3, 0xff }, |
@@ -55,8 +56,10 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe) | |||
55 | { 0x00427, 0x41, 0xff }, | 56 | { 0x00427, 0x41, 0xff }, |
56 | }; | 57 | }; |
57 | 58 | ||
58 | dev_dbg(&priv->i2c->dev, "%s: frequency=%d bandwidth_hz=%d\n", __func__, | 59 | dev_dbg(&client->dev, |
59 | c->frequency, c->bandwidth_hz); | 60 | "delivery_system=%d modulation=%d frequency=%u bandwidth_hz=%u inversion=%d\n", |
61 | c->delivery_system, c->modulation, c->frequency, | ||
62 | c->bandwidth_hz, c->inversion); | ||
60 | 63 | ||
61 | switch (c->bandwidth_hz) { | 64 | switch (c->bandwidth_hz) { |
62 | case 6000000: | 65 | case 6000000: |
@@ -80,12 +83,9 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe) | |||
80 | fe->ops.tuner_ops.set_params(fe); | 83 | fe->ops.tuner_ops.set_params(fe); |
81 | 84 | ||
82 | if (priv->delivery_system != SYS_DVBT) { | 85 | if (priv->delivery_system != SYS_DVBT) { |
83 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | 86 | ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab)); |
84 | ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, | 87 | if (ret) |
85 | tab[i].val, tab[i].mask); | 88 | goto error; |
86 | if (ret) | ||
87 | goto error; | ||
88 | } | ||
89 | } | 89 | } |
90 | 90 | ||
91 | priv->delivery_system = SYS_DVBT; | 91 | priv->delivery_system = SYS_DVBT; |
@@ -93,48 +93,46 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe) | |||
93 | 93 | ||
94 | /* program IF frequency */ | 94 | /* program IF frequency */ |
95 | if (fe->ops.tuner_ops.get_if_frequency) { | 95 | if (fe->ops.tuner_ops.get_if_frequency) { |
96 | ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); | 96 | ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); |
97 | if (ret) | 97 | if (ret) |
98 | goto error; | 98 | goto error; |
99 | } else | 99 | dev_dbg(&client->dev, "if_frequency=%u\n", if_frequency); |
100 | if_freq = 0; | 100 | } else { |
101 | 101 | ret = -EINVAL; | |
102 | dev_dbg(&priv->i2c->dev, "%s: if_freq=%d\n", __func__, if_freq); | 102 | goto error; |
103 | 103 | } | |
104 | num = if_freq / 1000; /* Hz => kHz */ | ||
105 | num *= 0x1000000; | ||
106 | if_ctl = DIV_ROUND_CLOSEST_ULL(num, 41000); | ||
107 | buf[0] = ((if_ctl >> 16) & 0xff); | ||
108 | buf[1] = ((if_ctl >> 8) & 0xff); | ||
109 | buf[2] = ((if_ctl >> 0) & 0xff); | ||
110 | 104 | ||
111 | ret = cxd2820r_wr_regs(priv, 0x000b6, buf, 3); | 105 | utmp = DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x1000000, CXD2820R_CLK); |
106 | buf[0] = (utmp >> 16) & 0xff; | ||
107 | buf[1] = (utmp >> 8) & 0xff; | ||
108 | buf[2] = (utmp >> 0) & 0xff; | ||
109 | ret = regmap_bulk_write(priv->regmap[0], 0x00b6, buf, 3); | ||
112 | if (ret) | 110 | if (ret) |
113 | goto error; | 111 | goto error; |
114 | 112 | ||
115 | ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[bw_i], 5); | 113 | ret = regmap_bulk_write(priv->regmap[0], 0x009f, bw_params1[bw_i], 5); |
116 | if (ret) | 114 | if (ret) |
117 | goto error; | 115 | goto error; |
118 | 116 | ||
119 | ret = cxd2820r_wr_reg_mask(priv, 0x000d7, bw_param << 6, 0xc0); | 117 | ret = regmap_update_bits(priv->regmap[0], 0x00d7, 0xc0, bw_param << 6); |
120 | if (ret) | 118 | if (ret) |
121 | goto error; | 119 | goto error; |
122 | 120 | ||
123 | ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[bw_i], 2); | 121 | ret = regmap_bulk_write(priv->regmap[0], 0x00d9, bw_params2[bw_i], 2); |
124 | if (ret) | 122 | if (ret) |
125 | goto error; | 123 | goto error; |
126 | 124 | ||
127 | ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08); | 125 | ret = regmap_write(priv->regmap[0], 0x00ff, 0x08); |
128 | if (ret) | 126 | if (ret) |
129 | goto error; | 127 | goto error; |
130 | 128 | ||
131 | ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01); | 129 | ret = regmap_write(priv->regmap[0], 0x00fe, 0x01); |
132 | if (ret) | 130 | if (ret) |
133 | goto error; | 131 | goto error; |
134 | 132 | ||
135 | return ret; | 133 | return ret; |
136 | error: | 134 | error: |
137 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 135 | dev_dbg(&client->dev, "failed=%d\n", ret); |
138 | return ret; | 136 | return ret; |
139 | } | 137 | } |
140 | 138 | ||
@@ -142,10 +140,14 @@ int cxd2820r_get_frontend_t(struct dvb_frontend *fe, | |||
142 | struct dtv_frontend_properties *c) | 140 | struct dtv_frontend_properties *c) |
143 | { | 141 | { |
144 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 142 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
143 | struct i2c_client *client = priv->client[0]; | ||
145 | int ret; | 144 | int ret; |
145 | unsigned int utmp; | ||
146 | u8 buf[2]; | 146 | u8 buf[2]; |
147 | 147 | ||
148 | ret = cxd2820r_rd_regs(priv, 0x0002f, buf, sizeof(buf)); | 148 | dev_dbg(&client->dev, "\n"); |
149 | |||
150 | ret = regmap_bulk_read(priv->regmap[0], 0x002f, buf, sizeof(buf)); | ||
149 | if (ret) | 151 | if (ret) |
150 | goto error; | 152 | goto error; |
151 | 153 | ||
@@ -236,11 +238,11 @@ int cxd2820r_get_frontend_t(struct dvb_frontend *fe, | |||
236 | break; | 238 | break; |
237 | } | 239 | } |
238 | 240 | ||
239 | ret = cxd2820r_rd_reg(priv, 0x007c6, &buf[0]); | 241 | ret = regmap_read(priv->regmap[0], 0x07c6, &utmp); |
240 | if (ret) | 242 | if (ret) |
241 | goto error; | 243 | goto error; |
242 | 244 | ||
243 | switch ((buf[0] >> 0) & 0x01) { | 245 | switch ((utmp >> 0) & 0x01) { |
244 | case 0: | 246 | case 0: |
245 | c->inversion = INVERSION_OFF; | 247 | c->inversion = INVERSION_OFF; |
246 | break; | 248 | break; |
@@ -251,169 +253,158 @@ int cxd2820r_get_frontend_t(struct dvb_frontend *fe, | |||
251 | 253 | ||
252 | return ret; | 254 | return ret; |
253 | error: | 255 | error: |
254 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 256 | dev_dbg(&client->dev, "failed=%d\n", ret); |
255 | return ret; | ||
256 | } | ||
257 | |||
258 | int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber) | ||
259 | { | ||
260 | struct cxd2820r_priv *priv = fe->demodulator_priv; | ||
261 | int ret; | ||
262 | u8 buf[3], start_ber = 0; | ||
263 | *ber = 0; | ||
264 | |||
265 | if (priv->ber_running) { | ||
266 | ret = cxd2820r_rd_regs(priv, 0x00076, buf, sizeof(buf)); | ||
267 | if (ret) | ||
268 | goto error; | ||
269 | |||
270 | if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) { | ||
271 | *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0]; | ||
272 | start_ber = 1; | ||
273 | } | ||
274 | } else { | ||
275 | priv->ber_running = true; | ||
276 | start_ber = 1; | ||
277 | } | ||
278 | |||
279 | if (start_ber) { | ||
280 | /* (re)start BER */ | ||
281 | ret = cxd2820r_wr_reg(priv, 0x00079, 0x01); | ||
282 | if (ret) | ||
283 | goto error; | ||
284 | } | ||
285 | |||
286 | return ret; | ||
287 | error: | ||
288 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
289 | return ret; | 257 | return ret; |
290 | } | 258 | } |
291 | 259 | ||
292 | int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe, | 260 | int cxd2820r_read_status_t(struct dvb_frontend *fe, enum fe_status *status) |
293 | u16 *strength) | ||
294 | { | 261 | { |
295 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 262 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
263 | struct i2c_client *client = priv->client[0]; | ||
264 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
296 | int ret; | 265 | int ret; |
297 | u8 buf[2]; | 266 | unsigned int utmp, utmp1, utmp2; |
298 | u16 tmp; | 267 | u8 buf[3]; |
299 | 268 | ||
300 | ret = cxd2820r_rd_regs(priv, 0x00026, buf, sizeof(buf)); | 269 | /* Lock detection */ |
270 | ret = regmap_bulk_read(priv->regmap[0], 0x0010, &buf[0], 1); | ||
271 | if (ret) | ||
272 | goto error; | ||
273 | ret = regmap_bulk_read(priv->regmap[0], 0x0073, &buf[1], 1); | ||
301 | if (ret) | 274 | if (ret) |
302 | goto error; | 275 | goto error; |
303 | 276 | ||
304 | tmp = (buf[0] & 0x0f) << 8 | buf[1]; | 277 | utmp1 = (buf[0] >> 0) & 0x07; |
305 | tmp = ~tmp & 0x0fff; | 278 | utmp2 = (buf[1] >> 3) & 0x01; |
306 | 279 | ||
307 | /* scale value to 0x0000-0xffff from 0x0000-0x0fff */ | 280 | if (utmp1 == 6 && utmp2 == 1) { |
308 | *strength = tmp * 0xffff / 0x0fff; | 281 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | |
282 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | ||
283 | } else if (utmp1 == 6 || utmp2 == 1) { | ||
284 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
285 | FE_HAS_VITERBI | FE_HAS_SYNC; | ||
286 | } else { | ||
287 | *status = 0; | ||
288 | } | ||
309 | 289 | ||
310 | return ret; | 290 | dev_dbg(&client->dev, "status=%02x raw=%*ph sync=%u ts=%u\n", |
311 | error: | 291 | *status, 2, buf, utmp1, utmp2); |
312 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
313 | return ret; | ||
314 | } | ||
315 | 292 | ||
316 | int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr) | 293 | /* Signal strength */ |
317 | { | 294 | if (*status & FE_HAS_SIGNAL) { |
318 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 295 | unsigned int strength; |
319 | int ret; | ||
320 | u8 buf[2]; | ||
321 | u16 tmp; | ||
322 | /* report SNR in dB * 10 */ | ||
323 | 296 | ||
324 | ret = cxd2820r_rd_regs(priv, 0x00028, buf, sizeof(buf)); | 297 | ret = regmap_bulk_read(priv->regmap[0], 0x0026, buf, 2); |
325 | if (ret) | 298 | if (ret) |
326 | goto error; | 299 | goto error; |
327 | 300 | ||
328 | tmp = (buf[0] & 0x1f) << 8 | buf[1]; | 301 | utmp = buf[0] << 8 | buf[1] << 0; |
329 | #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */ | 302 | utmp = ~utmp & 0x0fff; |
330 | if (tmp) | 303 | /* Scale value to 0x0000-0xffff */ |
331 | *snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24) | 304 | strength = utmp << 4 | utmp >> 8; |
332 | / 100); | ||
333 | else | ||
334 | *snr = 0; | ||
335 | 305 | ||
336 | dev_dbg(&priv->i2c->dev, "%s: dBx10=%d val=%04x\n", __func__, *snr, | 306 | c->strength.len = 1; |
337 | tmp); | 307 | c->strength.stat[0].scale = FE_SCALE_RELATIVE; |
308 | c->strength.stat[0].uvalue = strength; | ||
309 | } else { | ||
310 | c->strength.len = 1; | ||
311 | c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
312 | } | ||
338 | 313 | ||
339 | return ret; | 314 | /* CNR */ |
340 | error: | 315 | if (*status & FE_HAS_VITERBI) { |
341 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 316 | unsigned int cnr; |
342 | return ret; | ||
343 | } | ||
344 | 317 | ||
345 | int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks) | 318 | ret = regmap_bulk_read(priv->regmap[0], 0x002c, buf, 2); |
346 | { | 319 | if (ret) |
347 | *ucblocks = 0; | 320 | goto error; |
348 | /* no way to read ? */ | ||
349 | return 0; | ||
350 | } | ||
351 | 321 | ||
352 | int cxd2820r_read_status_t(struct dvb_frontend *fe, enum fe_status *status) | 322 | utmp = buf[0] << 8 | buf[1] << 0; |
353 | { | 323 | if (utmp) |
354 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 324 | cnr = div_u64((u64)(intlog10(utmp) |
355 | int ret; | 325 | - intlog10(32000 - utmp) + 55532585) |
356 | u8 buf[4]; | 326 | * 10000, (1 << 24)); |
357 | *status = 0; | 327 | else |
328 | cnr = 0; | ||
329 | |||
330 | c->cnr.len = 1; | ||
331 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; | ||
332 | c->cnr.stat[0].svalue = cnr; | ||
333 | } else { | ||
334 | c->cnr.len = 1; | ||
335 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
336 | } | ||
358 | 337 | ||
359 | ret = cxd2820r_rd_reg(priv, 0x00010, &buf[0]); | 338 | /* BER */ |
360 | if (ret) | 339 | if (*status & FE_HAS_SYNC) { |
361 | goto error; | 340 | unsigned int post_bit_error; |
341 | bool start_ber; | ||
362 | 342 | ||
363 | if ((buf[0] & 0x07) == 6) { | 343 | if (priv->ber_running) { |
364 | ret = cxd2820r_rd_reg(priv, 0x00073, &buf[1]); | 344 | ret = regmap_bulk_read(priv->regmap[0], 0x0076, buf, 3); |
365 | if (ret) | 345 | if (ret) |
366 | goto error; | 346 | goto error; |
367 | 347 | ||
368 | if (((buf[1] >> 3) & 0x01) == 1) { | 348 | if ((buf[2] >> 7) & 0x01) { |
369 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | 349 | post_bit_error = buf[2] << 16 | buf[1] << 8 | |
370 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | 350 | buf[0] << 0; |
351 | post_bit_error &= 0x0fffff; | ||
352 | start_ber = true; | ||
353 | } else { | ||
354 | post_bit_error = 0; | ||
355 | start_ber = false; | ||
356 | } | ||
371 | } else { | 357 | } else { |
372 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | 358 | post_bit_error = 0; |
373 | FE_HAS_VITERBI | FE_HAS_SYNC; | 359 | start_ber = true; |
374 | } | 360 | } |
375 | } else { | ||
376 | ret = cxd2820r_rd_reg(priv, 0x00014, &buf[2]); | ||
377 | if (ret) | ||
378 | goto error; | ||
379 | 361 | ||
380 | if ((buf[2] & 0x0f) >= 4) { | 362 | if (start_ber) { |
381 | ret = cxd2820r_rd_reg(priv, 0x00a14, &buf[3]); | 363 | ret = regmap_write(priv->regmap[0], 0x0079, 0x01); |
382 | if (ret) | 364 | if (ret) |
383 | goto error; | 365 | goto error; |
384 | 366 | priv->ber_running = true; | |
385 | if (((buf[3] >> 4) & 0x01) == 1) | ||
386 | *status |= FE_HAS_SIGNAL; | ||
387 | } | 367 | } |
388 | } | ||
389 | 368 | ||
390 | dev_dbg(&priv->i2c->dev, "%s: lock=%*ph\n", __func__, 4, buf); | 369 | priv->post_bit_error += post_bit_error; |
370 | |||
371 | c->post_bit_error.len = 1; | ||
372 | c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; | ||
373 | c->post_bit_error.stat[0].uvalue = priv->post_bit_error; | ||
374 | } else { | ||
375 | c->post_bit_error.len = 1; | ||
376 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
377 | } | ||
391 | 378 | ||
392 | return ret; | 379 | return ret; |
393 | error: | 380 | error: |
394 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 381 | dev_dbg(&client->dev, "failed=%d\n", ret); |
395 | return ret; | 382 | return ret; |
396 | } | 383 | } |
397 | 384 | ||
398 | int cxd2820r_init_t(struct dvb_frontend *fe) | 385 | int cxd2820r_init_t(struct dvb_frontend *fe) |
399 | { | 386 | { |
400 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 387 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
388 | struct i2c_client *client = priv->client[0]; | ||
401 | int ret; | 389 | int ret; |
402 | 390 | ||
403 | ret = cxd2820r_wr_reg(priv, 0x00085, 0x07); | 391 | dev_dbg(&client->dev, "\n"); |
392 | |||
393 | ret = regmap_write(priv->regmap[0], 0x0085, 0x07); | ||
404 | if (ret) | 394 | if (ret) |
405 | goto error; | 395 | goto error; |
406 | 396 | ||
407 | return ret; | 397 | return ret; |
408 | error: | 398 | error: |
409 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 399 | dev_dbg(&client->dev, "failed=%d\n", ret); |
410 | return ret; | 400 | return ret; |
411 | } | 401 | } |
412 | 402 | ||
413 | int cxd2820r_sleep_t(struct dvb_frontend *fe) | 403 | int cxd2820r_sleep_t(struct dvb_frontend *fe) |
414 | { | 404 | { |
415 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 405 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
416 | int ret, i; | 406 | struct i2c_client *client = priv->client[0]; |
407 | int ret; | ||
417 | struct reg_val_mask tab[] = { | 408 | struct reg_val_mask tab[] = { |
418 | { 0x000ff, 0x1f, 0xff }, | 409 | { 0x000ff, 0x1f, 0xff }, |
419 | { 0x00085, 0x00, 0xff }, | 410 | { 0x00085, 0x00, 0xff }, |
@@ -422,20 +413,17 @@ int cxd2820r_sleep_t(struct dvb_frontend *fe) | |||
422 | { 0x00080, 0x00, 0xff }, | 413 | { 0x00080, 0x00, 0xff }, |
423 | }; | 414 | }; |
424 | 415 | ||
425 | dev_dbg(&priv->i2c->dev, "%s\n", __func__); | 416 | dev_dbg(&client->dev, "\n"); |
426 | 417 | ||
427 | priv->delivery_system = SYS_UNDEFINED; | 418 | priv->delivery_system = SYS_UNDEFINED; |
428 | 419 | ||
429 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | 420 | ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab)); |
430 | ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val, | 421 | if (ret) |
431 | tab[i].mask); | 422 | goto error; |
432 | if (ret) | ||
433 | goto error; | ||
434 | } | ||
435 | 423 | ||
436 | return ret; | 424 | return ret; |
437 | error: | 425 | error: |
438 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 426 | dev_dbg(&client->dev, "failed=%d\n", ret); |
439 | return ret; | 427 | return ret; |
440 | } | 428 | } |
441 | 429 | ||
diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c index 704475676234..e641fde75379 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t2.c +++ b/drivers/media/dvb-frontends/cxd2820r_t2.c | |||
@@ -23,11 +23,12 @@ | |||
23 | 23 | ||
24 | int cxd2820r_set_frontend_t2(struct dvb_frontend *fe) | 24 | int cxd2820r_set_frontend_t2(struct dvb_frontend *fe) |
25 | { | 25 | { |
26 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
27 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 26 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
28 | int ret, i, bw_i; | 27 | struct i2c_client *client = priv->client[0]; |
29 | u32 if_freq, if_ctl; | 28 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
30 | u64 num; | 29 | int ret, bw_i; |
30 | unsigned int utmp; | ||
31 | u32 if_frequency; | ||
31 | u8 buf[3], bw_param; | 32 | u8 buf[3], bw_param; |
32 | u8 bw_params1[][5] = { | 33 | u8 bw_params1[][5] = { |
33 | { 0x1c, 0xb3, 0x33, 0x33, 0x33 }, /* 5 MHz */ | 34 | { 0x1c, 0xb3, 0x33, 0x33, 0x33 }, /* 5 MHz */ |
@@ -45,10 +46,10 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe) | |||
45 | { 0x0207f, 0x2a, 0xff }, | 46 | { 0x0207f, 0x2a, 0xff }, |
46 | { 0x02082, 0x0a, 0xff }, | 47 | { 0x02082, 0x0a, 0xff }, |
47 | { 0x02083, 0x0a, 0xff }, | 48 | { 0x02083, 0x0a, 0xff }, |
48 | { 0x020cb, priv->cfg.if_agc_polarity << 6, 0x40 }, | 49 | { 0x020cb, priv->if_agc_polarity << 6, 0x40 }, |
49 | { 0x02070, priv->cfg.ts_mode, 0xff }, | 50 | { 0x02070, priv->ts_mode, 0xff }, |
50 | { 0x02071, !priv->cfg.ts_clock_inv << 6, 0x40 }, | 51 | { 0x02071, !priv->ts_clk_inv << 6, 0x40 }, |
51 | { 0x020b5, priv->cfg.spec_inv << 4, 0x10 }, | 52 | { 0x020b5, priv->spec_inv << 4, 0x10 }, |
52 | { 0x02567, 0x07, 0x0f }, | 53 | { 0x02567, 0x07, 0x0f }, |
53 | { 0x02569, 0x03, 0x03 }, | 54 | { 0x02569, 0x03, 0x03 }, |
54 | { 0x02595, 0x1a, 0xff }, | 55 | { 0x02595, 0x1a, 0xff }, |
@@ -69,8 +70,10 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe) | |||
69 | { 0x027ef, 0x10, 0x18 }, | 70 | { 0x027ef, 0x10, 0x18 }, |
70 | }; | 71 | }; |
71 | 72 | ||
72 | dev_dbg(&priv->i2c->dev, "%s: frequency=%d bandwidth_hz=%d\n", __func__, | 73 | dev_dbg(&client->dev, |
73 | c->frequency, c->bandwidth_hz); | 74 | "delivery_system=%d modulation=%d frequency=%u bandwidth_hz=%u inversion=%d stream_id=%u\n", |
75 | c->delivery_system, c->modulation, c->frequency, | ||
76 | c->bandwidth_hz, c->inversion, c->stream_id); | ||
74 | 77 | ||
75 | switch (c->bandwidth_hz) { | 78 | switch (c->bandwidth_hz) { |
76 | case 5000000: | 79 | case 5000000: |
@@ -98,73 +101,67 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe) | |||
98 | fe->ops.tuner_ops.set_params(fe); | 101 | fe->ops.tuner_ops.set_params(fe); |
99 | 102 | ||
100 | if (priv->delivery_system != SYS_DVBT2) { | 103 | if (priv->delivery_system != SYS_DVBT2) { |
101 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | 104 | ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab)); |
102 | ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, | 105 | if (ret) |
103 | tab[i].val, tab[i].mask); | 106 | goto error; |
104 | if (ret) | ||
105 | goto error; | ||
106 | } | ||
107 | } | 107 | } |
108 | 108 | ||
109 | priv->delivery_system = SYS_DVBT2; | 109 | priv->delivery_system = SYS_DVBT2; |
110 | 110 | ||
111 | /* program IF frequency */ | 111 | /* program IF frequency */ |
112 | if (fe->ops.tuner_ops.get_if_frequency) { | 112 | if (fe->ops.tuner_ops.get_if_frequency) { |
113 | ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); | 113 | ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); |
114 | if (ret) | 114 | if (ret) |
115 | goto error; | 115 | goto error; |
116 | } else | 116 | dev_dbg(&client->dev, "if_frequency=%u\n", if_frequency); |
117 | if_freq = 0; | 117 | } else { |
118 | 118 | ret = -EINVAL; | |
119 | dev_dbg(&priv->i2c->dev, "%s: if_freq=%d\n", __func__, if_freq); | 119 | goto error; |
120 | } | ||
120 | 121 | ||
121 | num = if_freq / 1000; /* Hz => kHz */ | 122 | utmp = DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x1000000, CXD2820R_CLK); |
122 | num *= 0x1000000; | 123 | buf[0] = (utmp >> 16) & 0xff; |
123 | if_ctl = DIV_ROUND_CLOSEST_ULL(num, 41000); | 124 | buf[1] = (utmp >> 8) & 0xff; |
124 | buf[0] = ((if_ctl >> 16) & 0xff); | 125 | buf[2] = (utmp >> 0) & 0xff; |
125 | buf[1] = ((if_ctl >> 8) & 0xff); | 126 | ret = regmap_bulk_write(priv->regmap[0], 0x20b6, buf, 3); |
126 | buf[2] = ((if_ctl >> 0) & 0xff); | 127 | if (ret) |
128 | goto error; | ||
127 | 129 | ||
128 | /* PLP filtering */ | 130 | /* PLP filtering */ |
129 | if (c->stream_id > 255) { | 131 | if (c->stream_id > 255) { |
130 | dev_dbg(&priv->i2c->dev, "%s: Disable PLP filtering\n", __func__); | 132 | dev_dbg(&client->dev, "disable PLP filtering\n"); |
131 | ret = cxd2820r_wr_reg(priv, 0x023ad , 0); | 133 | ret = regmap_write(priv->regmap[0], 0x23ad, 0x00); |
132 | if (ret) | 134 | if (ret) |
133 | goto error; | 135 | goto error; |
134 | } else { | 136 | } else { |
135 | dev_dbg(&priv->i2c->dev, "%s: Enable PLP filtering = %d\n", __func__, | 137 | dev_dbg(&client->dev, "enable PLP filtering\n"); |
136 | c->stream_id); | 138 | ret = regmap_write(priv->regmap[0], 0x23af, c->stream_id & 0xff); |
137 | ret = cxd2820r_wr_reg(priv, 0x023af , c->stream_id & 0xFF); | ||
138 | if (ret) | 139 | if (ret) |
139 | goto error; | 140 | goto error; |
140 | ret = cxd2820r_wr_reg(priv, 0x023ad , 1); | 141 | ret = regmap_write(priv->regmap[0], 0x23ad, 0x01); |
141 | if (ret) | 142 | if (ret) |
142 | goto error; | 143 | goto error; |
143 | } | 144 | } |
144 | 145 | ||
145 | ret = cxd2820r_wr_regs(priv, 0x020b6, buf, 3); | 146 | ret = regmap_bulk_write(priv->regmap[0], 0x209f, bw_params1[bw_i], 5); |
146 | if (ret) | 147 | if (ret) |
147 | goto error; | 148 | goto error; |
148 | 149 | ||
149 | ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[bw_i], 5); | 150 | ret = regmap_update_bits(priv->regmap[0], 0x20d7, 0xc0, bw_param << 6); |
150 | if (ret) | 151 | if (ret) |
151 | goto error; | 152 | goto error; |
152 | 153 | ||
153 | ret = cxd2820r_wr_reg_mask(priv, 0x020d7, bw_param << 6, 0xc0); | 154 | ret = regmap_write(priv->regmap[0], 0x00ff, 0x08); |
154 | if (ret) | 155 | if (ret) |
155 | goto error; | 156 | goto error; |
156 | 157 | ||
157 | ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08); | 158 | ret = regmap_write(priv->regmap[0], 0x00fe, 0x01); |
158 | if (ret) | ||
159 | goto error; | ||
160 | |||
161 | ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01); | ||
162 | if (ret) | 159 | if (ret) |
163 | goto error; | 160 | goto error; |
164 | 161 | ||
165 | return ret; | 162 | return ret; |
166 | error: | 163 | error: |
167 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 164 | dev_dbg(&client->dev, "failed=%d\n", ret); |
168 | return ret; | 165 | return ret; |
169 | 166 | ||
170 | } | 167 | } |
@@ -173,10 +170,14 @@ int cxd2820r_get_frontend_t2(struct dvb_frontend *fe, | |||
173 | struct dtv_frontend_properties *c) | 170 | struct dtv_frontend_properties *c) |
174 | { | 171 | { |
175 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 172 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
173 | struct i2c_client *client = priv->client[0]; | ||
176 | int ret; | 174 | int ret; |
175 | unsigned int utmp; | ||
177 | u8 buf[2]; | 176 | u8 buf[2]; |
178 | 177 | ||
179 | ret = cxd2820r_rd_regs(priv, 0x0205c, buf, 2); | 178 | dev_dbg(&client->dev, "\n"); |
179 | |||
180 | ret = regmap_bulk_read(priv->regmap[0], 0x205c, buf, 2); | ||
180 | if (ret) | 181 | if (ret) |
181 | goto error; | 182 | goto error; |
182 | 183 | ||
@@ -225,7 +226,7 @@ int cxd2820r_get_frontend_t2(struct dvb_frontend *fe, | |||
225 | break; | 226 | break; |
226 | } | 227 | } |
227 | 228 | ||
228 | ret = cxd2820r_rd_regs(priv, 0x0225b, buf, 2); | 229 | ret = regmap_bulk_read(priv->regmap[0], 0x225b, buf, 2); |
229 | if (ret) | 230 | if (ret) |
230 | goto error; | 231 | goto error; |
231 | 232 | ||
@@ -265,11 +266,11 @@ int cxd2820r_get_frontend_t2(struct dvb_frontend *fe, | |||
265 | break; | 266 | break; |
266 | } | 267 | } |
267 | 268 | ||
268 | ret = cxd2820r_rd_reg(priv, 0x020b5, &buf[0]); | 269 | ret = regmap_read(priv->regmap[0], 0x20b5, &utmp); |
269 | if (ret) | 270 | if (ret) |
270 | goto error; | 271 | goto error; |
271 | 272 | ||
272 | switch ((buf[0] >> 4) & 0x01) { | 273 | switch ((utmp >> 4) & 0x01) { |
273 | case 0: | 274 | case 0: |
274 | c->inversion = INVERSION_OFF; | 275 | c->inversion = INVERSION_OFF; |
275 | break; | 276 | break; |
@@ -280,130 +281,124 @@ int cxd2820r_get_frontend_t2(struct dvb_frontend *fe, | |||
280 | 281 | ||
281 | return ret; | 282 | return ret; |
282 | error: | 283 | error: |
283 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 284 | dev_dbg(&client->dev, "failed=%d\n", ret); |
284 | return ret; | 285 | return ret; |
285 | } | 286 | } |
286 | 287 | ||
287 | int cxd2820r_read_status_t2(struct dvb_frontend *fe, enum fe_status *status) | 288 | int cxd2820r_read_status_t2(struct dvb_frontend *fe, enum fe_status *status) |
288 | { | 289 | { |
289 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 290 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
291 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
292 | struct i2c_client *client = priv->client[0]; | ||
290 | int ret; | 293 | int ret; |
291 | u8 buf[1]; | 294 | unsigned int utmp, utmp1, utmp2; |
292 | *status = 0; | 295 | u8 buf[4]; |
293 | 296 | ||
294 | ret = cxd2820r_rd_reg(priv, 0x02010 , &buf[0]); | 297 | /* Lock detection */ |
298 | ret = regmap_bulk_read(priv->regmap[0], 0x2010, &buf[0], 1); | ||
295 | if (ret) | 299 | if (ret) |
296 | goto error; | 300 | goto error; |
297 | 301 | ||
298 | if ((buf[0] & 0x07) == 6) { | 302 | utmp1 = (buf[0] >> 0) & 0x07; |
299 | if (((buf[0] >> 5) & 0x01) == 1) { | 303 | utmp2 = (buf[0] >> 5) & 0x01; |
300 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
301 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | ||
302 | } else { | ||
303 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
304 | FE_HAS_VITERBI | FE_HAS_SYNC; | ||
305 | } | ||
306 | } | ||
307 | 304 | ||
308 | dev_dbg(&priv->i2c->dev, "%s: lock=%02x\n", __func__, buf[0]); | 305 | if (utmp1 == 6 && utmp2 == 1) { |
306 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
307 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | ||
308 | } else if (utmp1 == 6 || utmp2 == 1) { | ||
309 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
310 | FE_HAS_VITERBI | FE_HAS_SYNC; | ||
311 | } else { | ||
312 | *status = 0; | ||
313 | } | ||
309 | 314 | ||
310 | return ret; | 315 | dev_dbg(&client->dev, "status=%02x raw=%*ph sync=%u ts=%u\n", |
311 | error: | 316 | *status, 1, buf, utmp1, utmp2); |
312 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
313 | return ret; | ||
314 | } | ||
315 | 317 | ||
316 | int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber) | 318 | /* Signal strength */ |
317 | { | 319 | if (*status & FE_HAS_SIGNAL) { |
318 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 320 | unsigned int strength; |
319 | int ret; | ||
320 | u8 buf[4]; | ||
321 | unsigned int errbits; | ||
322 | *ber = 0; | ||
323 | /* FIXME: correct calculation */ | ||
324 | 321 | ||
325 | ret = cxd2820r_rd_regs(priv, 0x02039, buf, sizeof(buf)); | 322 | ret = regmap_bulk_read(priv->regmap[0], 0x2026, buf, 2); |
326 | if (ret) | 323 | if (ret) |
327 | goto error; | 324 | goto error; |
328 | 325 | ||
329 | if ((buf[0] >> 4) & 0x01) { | 326 | utmp = buf[0] << 8 | buf[1] << 0; |
330 | errbits = (buf[0] & 0x0f) << 24 | buf[1] << 16 | | 327 | utmp = ~utmp & 0x0fff; |
331 | buf[2] << 8 | buf[3]; | 328 | /* Scale value to 0x0000-0xffff */ |
329 | strength = utmp << 4 | utmp >> 8; | ||
332 | 330 | ||
333 | if (errbits) | 331 | c->strength.len = 1; |
334 | *ber = errbits * 64 / 16588800; | 332 | c->strength.stat[0].scale = FE_SCALE_RELATIVE; |
333 | c->strength.stat[0].uvalue = strength; | ||
334 | } else { | ||
335 | c->strength.len = 1; | ||
336 | c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
335 | } | 337 | } |
336 | 338 | ||
337 | return ret; | 339 | /* CNR */ |
338 | error: | 340 | if (*status & FE_HAS_VITERBI) { |
339 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 341 | unsigned int cnr; |
340 | return ret; | ||
341 | } | ||
342 | 342 | ||
343 | int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe, | 343 | ret = regmap_bulk_read(priv->regmap[0], 0x2028, buf, 2); |
344 | u16 *strength) | 344 | if (ret) |
345 | { | 345 | goto error; |
346 | struct cxd2820r_priv *priv = fe->demodulator_priv; | ||
347 | int ret; | ||
348 | u8 buf[2]; | ||
349 | u16 tmp; | ||
350 | |||
351 | ret = cxd2820r_rd_regs(priv, 0x02026, buf, sizeof(buf)); | ||
352 | if (ret) | ||
353 | goto error; | ||
354 | |||
355 | tmp = (buf[0] & 0x0f) << 8 | buf[1]; | ||
356 | tmp = ~tmp & 0x0fff; | ||
357 | 346 | ||
358 | /* scale value to 0x0000-0xffff from 0x0000-0x0fff */ | 347 | utmp = buf[0] << 8 | buf[1] << 0; |
359 | *strength = tmp * 0xffff / 0x0fff; | 348 | utmp = utmp & 0x0fff; |
349 | #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */ | ||
350 | if (utmp) | ||
351 | cnr = div_u64((u64)(intlog10(utmp) | ||
352 | - CXD2820R_LOG10_8_24) * 10000, | ||
353 | (1 << 24)); | ||
354 | else | ||
355 | cnr = 0; | ||
356 | |||
357 | c->cnr.len = 1; | ||
358 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; | ||
359 | c->cnr.stat[0].svalue = cnr; | ||
360 | } else { | ||
361 | c->cnr.len = 1; | ||
362 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
363 | } | ||
360 | 364 | ||
361 | return ret; | 365 | /* BER */ |
362 | error: | 366 | if (*status & FE_HAS_SYNC) { |
363 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 367 | unsigned int post_bit_error; |
364 | return ret; | ||
365 | } | ||
366 | 368 | ||
367 | int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr) | 369 | ret = regmap_bulk_read(priv->regmap[0], 0x2039, buf, 4); |
368 | { | 370 | if (ret) |
369 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 371 | goto error; |
370 | int ret; | ||
371 | u8 buf[2]; | ||
372 | u16 tmp; | ||
373 | /* report SNR in dB * 10 */ | ||
374 | 372 | ||
375 | ret = cxd2820r_rd_regs(priv, 0x02028, buf, sizeof(buf)); | 373 | if ((buf[0] >> 4) & 0x01) { |
376 | if (ret) | 374 | post_bit_error = buf[0] << 24 | buf[1] << 16 | |
377 | goto error; | 375 | buf[2] << 8 | buf[3] << 0; |
376 | post_bit_error &= 0x0fffffff; | ||
377 | } else { | ||
378 | post_bit_error = 0; | ||
379 | } | ||
378 | 380 | ||
379 | tmp = (buf[0] & 0x0f) << 8 | buf[1]; | 381 | priv->post_bit_error += post_bit_error; |
380 | #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */ | ||
381 | if (tmp) | ||
382 | *snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24) | ||
383 | / 100); | ||
384 | else | ||
385 | *snr = 0; | ||
386 | 382 | ||
387 | dev_dbg(&priv->i2c->dev, "%s: dBx10=%d val=%04x\n", __func__, *snr, | 383 | c->post_bit_error.len = 1; |
388 | tmp); | 384 | c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; |
385 | c->post_bit_error.stat[0].uvalue = priv->post_bit_error; | ||
386 | } else { | ||
387 | c->post_bit_error.len = 1; | ||
388 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
389 | } | ||
389 | 390 | ||
390 | return ret; | 391 | return ret; |
391 | error: | 392 | error: |
392 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 393 | dev_dbg(&client->dev, "failed=%d\n", ret); |
393 | return ret; | 394 | return ret; |
394 | } | 395 | } |
395 | 396 | ||
396 | int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks) | ||
397 | { | ||
398 | *ucblocks = 0; | ||
399 | /* no way to read ? */ | ||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | int cxd2820r_sleep_t2(struct dvb_frontend *fe) | 397 | int cxd2820r_sleep_t2(struct dvb_frontend *fe) |
404 | { | 398 | { |
405 | struct cxd2820r_priv *priv = fe->demodulator_priv; | 399 | struct cxd2820r_priv *priv = fe->demodulator_priv; |
406 | int ret, i; | 400 | struct i2c_client *client = priv->client[0]; |
401 | int ret; | ||
407 | struct reg_val_mask tab[] = { | 402 | struct reg_val_mask tab[] = { |
408 | { 0x000ff, 0x1f, 0xff }, | 403 | { 0x000ff, 0x1f, 0xff }, |
409 | { 0x00085, 0x00, 0xff }, | 404 | { 0x00085, 0x00, 0xff }, |
@@ -413,20 +408,17 @@ int cxd2820r_sleep_t2(struct dvb_frontend *fe) | |||
413 | { 0x00080, 0x00, 0xff }, | 408 | { 0x00080, 0x00, 0xff }, |
414 | }; | 409 | }; |
415 | 410 | ||
416 | dev_dbg(&priv->i2c->dev, "%s\n", __func__); | 411 | dev_dbg(&client->dev, "\n"); |
417 | 412 | ||
418 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | 413 | ret = cxd2820r_wr_reg_val_mask_tab(priv, tab, ARRAY_SIZE(tab)); |
419 | ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val, | 414 | if (ret) |
420 | tab[i].mask); | 415 | goto error; |
421 | if (ret) | ||
422 | goto error; | ||
423 | } | ||
424 | 416 | ||
425 | priv->delivery_system = SYS_UNDEFINED; | 417 | priv->delivery_system = SYS_UNDEFINED; |
426 | 418 | ||
427 | return ret; | 419 | return ret; |
428 | error: | 420 | error: |
429 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | 421 | dev_dbg(&client->dev, "failed=%d\n", ret); |
430 | return ret; | 422 | return ret; |
431 | } | 423 | } |
432 | 424 | ||
diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c index ffe88bc6b813..5afb9c508f65 100644 --- a/drivers/media/dvb-frontends/cxd2841er.c +++ b/drivers/media/dvb-frontends/cxd2841er.c | |||
@@ -206,6 +206,9 @@ static const struct cxd2841er_cnr_data s2_cn_data[] = { | |||
206 | (u32)(((iffreq)/48.0)*16777216.0 + 0.5) : \ | 206 | (u32)(((iffreq)/48.0)*16777216.0 + 0.5) : \ |
207 | (u32)(((iffreq)/41.0)*16777216.0 + 0.5)) | 207 | (u32)(((iffreq)/41.0)*16777216.0 + 0.5)) |
208 | 208 | ||
209 | static int cxd2841er_freeze_regs(struct cxd2841er_priv *priv); | ||
210 | static int cxd2841er_unfreeze_regs(struct cxd2841er_priv *priv); | ||
211 | |||
209 | static void cxd2841er_i2c_debug(struct cxd2841er_priv *priv, | 212 | static void cxd2841er_i2c_debug(struct cxd2841er_priv *priv, |
210 | u8 addr, u8 reg, u8 write, | 213 | u8 addr, u8 reg, u8 write, |
211 | const u8 *data, u32 len) | 214 | const u8 *data, u32 len) |
@@ -1401,6 +1404,41 @@ static int cxd2841er_read_ber_c(struct cxd2841er_priv *priv, | |||
1401 | return 0; | 1404 | return 0; |
1402 | } | 1405 | } |
1403 | 1406 | ||
1407 | static int cxd2841er_read_ber_i(struct cxd2841er_priv *priv, | ||
1408 | u32 *bit_error, u32 *bit_count) | ||
1409 | { | ||
1410 | u8 data[3]; | ||
1411 | u8 pktnum[2]; | ||
1412 | |||
1413 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
1414 | if (priv->state != STATE_ACTIVE_TC) { | ||
1415 | dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n", | ||
1416 | __func__, priv->state); | ||
1417 | return -EINVAL; | ||
1418 | } | ||
1419 | |||
1420 | cxd2841er_freeze_regs(priv); | ||
1421 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); | ||
1422 | cxd2841er_read_regs(priv, I2C_SLVT, 0x5B, pktnum, sizeof(pktnum)); | ||
1423 | cxd2841er_read_regs(priv, I2C_SLVT, 0x16, data, sizeof(data)); | ||
1424 | |||
1425 | if (!pktnum[0] && !pktnum[1]) { | ||
1426 | dev_dbg(&priv->i2c->dev, | ||
1427 | "%s(): no valid BER data\n", __func__); | ||
1428 | cxd2841er_unfreeze_regs(priv); | ||
1429 | return -EINVAL; | ||
1430 | } | ||
1431 | |||
1432 | *bit_error = ((u32)(data[0] & 0x7F) << 16) | | ||
1433 | ((u32)data[1] << 8) | data[2]; | ||
1434 | *bit_count = ((((u32)pktnum[0] << 8) | pktnum[1]) * 204 * 8); | ||
1435 | dev_dbg(&priv->i2c->dev, "%s(): bit_error=%u bit_count=%u\n", | ||
1436 | __func__, *bit_error, *bit_count); | ||
1437 | |||
1438 | cxd2841er_unfreeze_regs(priv); | ||
1439 | return 0; | ||
1440 | } | ||
1441 | |||
1404 | static int cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv, | 1442 | static int cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv, |
1405 | u32 *bit_error, u32 *bit_count) | 1443 | u32 *bit_error, u32 *bit_count) |
1406 | { | 1444 | { |
@@ -1570,6 +1608,25 @@ static int cxd2841er_read_ber_t(struct cxd2841er_priv *priv, | |||
1570 | return 0; | 1608 | return 0; |
1571 | } | 1609 | } |
1572 | 1610 | ||
1611 | static int cxd2841er_freeze_regs(struct cxd2841er_priv *priv) | ||
1612 | { | ||
1613 | /* | ||
1614 | * Freeze registers: ensure multiple separate register reads | ||
1615 | * are from the same snapshot | ||
1616 | */ | ||
1617 | cxd2841er_write_reg(priv, I2C_SLVT, 0x01, 0x01); | ||
1618 | return 0; | ||
1619 | } | ||
1620 | |||
1621 | static int cxd2841er_unfreeze_regs(struct cxd2841er_priv *priv) | ||
1622 | { | ||
1623 | /* | ||
1624 | * un-freeze registers | ||
1625 | */ | ||
1626 | cxd2841er_write_reg(priv, I2C_SLVT, 0x01, 0x00); | ||
1627 | return 0; | ||
1628 | } | ||
1629 | |||
1573 | static u32 cxd2841er_dvbs_read_snr(struct cxd2841er_priv *priv, | 1630 | static u32 cxd2841er_dvbs_read_snr(struct cxd2841er_priv *priv, |
1574 | u8 delsys, u32 *snr) | 1631 | u8 delsys, u32 *snr) |
1575 | { | 1632 | { |
@@ -1578,6 +1635,7 @@ static u32 cxd2841er_dvbs_read_snr(struct cxd2841er_priv *priv, | |||
1578 | int min_index, max_index, index; | 1635 | int min_index, max_index, index; |
1579 | static const struct cxd2841er_cnr_data *cn_data; | 1636 | static const struct cxd2841er_cnr_data *cn_data; |
1580 | 1637 | ||
1638 | cxd2841er_freeze_regs(priv); | ||
1581 | /* Set SLV-T Bank : 0xA1 */ | 1639 | /* Set SLV-T Bank : 0xA1 */ |
1582 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa1); | 1640 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa1); |
1583 | /* | 1641 | /* |
@@ -1629,9 +1687,11 @@ static u32 cxd2841er_dvbs_read_snr(struct cxd2841er_priv *priv, | |||
1629 | } else { | 1687 | } else { |
1630 | dev_dbg(&priv->i2c->dev, | 1688 | dev_dbg(&priv->i2c->dev, |
1631 | "%s(): no data available\n", __func__); | 1689 | "%s(): no data available\n", __func__); |
1690 | cxd2841er_unfreeze_regs(priv); | ||
1632 | return -EINVAL; | 1691 | return -EINVAL; |
1633 | } | 1692 | } |
1634 | done: | 1693 | done: |
1694 | cxd2841er_unfreeze_regs(priv); | ||
1635 | *snr = res; | 1695 | *snr = res; |
1636 | return 0; | 1696 | return 0; |
1637 | } | 1697 | } |
@@ -1655,12 +1715,7 @@ static int cxd2841er_read_snr_c(struct cxd2841er_priv *priv, u32 *snr) | |||
1655 | return -EINVAL; | 1715 | return -EINVAL; |
1656 | } | 1716 | } |
1657 | 1717 | ||
1658 | /* | 1718 | cxd2841er_freeze_regs(priv); |
1659 | * Freeze registers: ensure multiple separate register reads | ||
1660 | * are from the same snapshot | ||
1661 | */ | ||
1662 | cxd2841er_write_reg(priv, I2C_SLVT, 0x01, 0x01); | ||
1663 | |||
1664 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40); | 1719 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40); |
1665 | cxd2841er_read_regs(priv, I2C_SLVT, 0x19, data, 1); | 1720 | cxd2841er_read_regs(priv, I2C_SLVT, 0x19, data, 1); |
1666 | qam = (enum sony_dvbc_constellation_t) (data[0] & 0x07); | 1721 | qam = (enum sony_dvbc_constellation_t) (data[0] & 0x07); |
@@ -1670,6 +1725,7 @@ static int cxd2841er_read_snr_c(struct cxd2841er_priv *priv, u32 *snr) | |||
1670 | if (reg == 0) { | 1725 | if (reg == 0) { |
1671 | dev_dbg(&priv->i2c->dev, | 1726 | dev_dbg(&priv->i2c->dev, |
1672 | "%s(): reg value out of range\n", __func__); | 1727 | "%s(): reg value out of range\n", __func__); |
1728 | cxd2841er_unfreeze_regs(priv); | ||
1673 | return 0; | 1729 | return 0; |
1674 | } | 1730 | } |
1675 | 1731 | ||
@@ -1690,9 +1746,11 @@ static int cxd2841er_read_snr_c(struct cxd2841er_priv *priv, u32 *snr) | |||
1690 | *snr = -88 * (int32_t)sony_log(reg) + 86999; | 1746 | *snr = -88 * (int32_t)sony_log(reg) + 86999; |
1691 | break; | 1747 | break; |
1692 | default: | 1748 | default: |
1749 | cxd2841er_unfreeze_regs(priv); | ||
1693 | return -EINVAL; | 1750 | return -EINVAL; |
1694 | } | 1751 | } |
1695 | 1752 | ||
1753 | cxd2841er_unfreeze_regs(priv); | ||
1696 | return 0; | 1754 | return 0; |
1697 | } | 1755 | } |
1698 | 1756 | ||
@@ -1707,17 +1765,21 @@ static int cxd2841er_read_snr_t(struct cxd2841er_priv *priv, u32 *snr) | |||
1707 | "%s(): invalid state %d\n", __func__, priv->state); | 1765 | "%s(): invalid state %d\n", __func__, priv->state); |
1708 | return -EINVAL; | 1766 | return -EINVAL; |
1709 | } | 1767 | } |
1768 | |||
1769 | cxd2841er_freeze_regs(priv); | ||
1710 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | 1770 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
1711 | cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data)); | 1771 | cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data)); |
1712 | reg = ((u32)data[0] << 8) | (u32)data[1]; | 1772 | reg = ((u32)data[0] << 8) | (u32)data[1]; |
1713 | if (reg == 0) { | 1773 | if (reg == 0) { |
1714 | dev_dbg(&priv->i2c->dev, | 1774 | dev_dbg(&priv->i2c->dev, |
1715 | "%s(): reg value out of range\n", __func__); | 1775 | "%s(): reg value out of range\n", __func__); |
1776 | cxd2841er_unfreeze_regs(priv); | ||
1716 | return 0; | 1777 | return 0; |
1717 | } | 1778 | } |
1718 | if (reg > 4996) | 1779 | if (reg > 4996) |
1719 | reg = 4996; | 1780 | reg = 4996; |
1720 | *snr = 10000 * ((intlog10(reg) - intlog10(5350 - reg)) >> 24) + 28500; | 1781 | *snr = 10000 * ((intlog10(reg) - intlog10(5350 - reg)) >> 24) + 28500; |
1782 | cxd2841er_unfreeze_regs(priv); | ||
1721 | return 0; | 1783 | return 0; |
1722 | } | 1784 | } |
1723 | 1785 | ||
@@ -1732,18 +1794,22 @@ static int cxd2841er_read_snr_t2(struct cxd2841er_priv *priv, u32 *snr) | |||
1732 | "%s(): invalid state %d\n", __func__, priv->state); | 1794 | "%s(): invalid state %d\n", __func__, priv->state); |
1733 | return -EINVAL; | 1795 | return -EINVAL; |
1734 | } | 1796 | } |
1797 | |||
1798 | cxd2841er_freeze_regs(priv); | ||
1735 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20); | 1799 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20); |
1736 | cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data)); | 1800 | cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data)); |
1737 | reg = ((u32)data[0] << 8) | (u32)data[1]; | 1801 | reg = ((u32)data[0] << 8) | (u32)data[1]; |
1738 | if (reg == 0) { | 1802 | if (reg == 0) { |
1739 | dev_dbg(&priv->i2c->dev, | 1803 | dev_dbg(&priv->i2c->dev, |
1740 | "%s(): reg value out of range\n", __func__); | 1804 | "%s(): reg value out of range\n", __func__); |
1805 | cxd2841er_unfreeze_regs(priv); | ||
1741 | return 0; | 1806 | return 0; |
1742 | } | 1807 | } |
1743 | if (reg > 10876) | 1808 | if (reg > 10876) |
1744 | reg = 10876; | 1809 | reg = 10876; |
1745 | *snr = 10000 * ((intlog10(reg) - | 1810 | *snr = 10000 * ((intlog10(reg) - |
1746 | intlog10(12600 - reg)) >> 24) + 32000; | 1811 | intlog10(12600 - reg)) >> 24) + 32000; |
1812 | cxd2841er_unfreeze_regs(priv); | ||
1747 | return 0; | 1813 | return 0; |
1748 | } | 1814 | } |
1749 | 1815 | ||
@@ -1760,21 +1826,18 @@ static int cxd2841er_read_snr_i(struct cxd2841er_priv *priv, u32 *snr) | |||
1760 | return -EINVAL; | 1826 | return -EINVAL; |
1761 | } | 1827 | } |
1762 | 1828 | ||
1763 | /* Freeze all registers */ | 1829 | cxd2841er_freeze_regs(priv); |
1764 | cxd2841er_write_reg(priv, I2C_SLVT, 0x01, 0x01); | ||
1765 | |||
1766 | |||
1767 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); | 1830 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); |
1768 | cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data)); | 1831 | cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data)); |
1769 | reg = ((u32)data[0] << 8) | (u32)data[1]; | 1832 | reg = ((u32)data[0] << 8) | (u32)data[1]; |
1770 | if (reg == 0) { | 1833 | if (reg == 0) { |
1771 | dev_dbg(&priv->i2c->dev, | 1834 | dev_dbg(&priv->i2c->dev, |
1772 | "%s(): reg value out of range\n", __func__); | 1835 | "%s(): reg value out of range\n", __func__); |
1836 | cxd2841er_unfreeze_regs(priv); | ||
1773 | return 0; | 1837 | return 0; |
1774 | } | 1838 | } |
1775 | if (reg > 4996) | 1839 | *snr = 10000 * (intlog10(reg) >> 24) - 9031; |
1776 | reg = 4996; | 1840 | cxd2841er_unfreeze_regs(priv); |
1777 | *snr = 100 * intlog10(reg) - 9031; | ||
1778 | return 0; | 1841 | return 0; |
1779 | } | 1842 | } |
1780 | 1843 | ||
@@ -1852,6 +1915,9 @@ static void cxd2841er_read_ber(struct dvb_frontend *fe) | |||
1852 | case SYS_DVBC_ANNEX_C: | 1915 | case SYS_DVBC_ANNEX_C: |
1853 | ret = cxd2841er_read_ber_c(priv, &bit_error, &bit_count); | 1916 | ret = cxd2841er_read_ber_c(priv, &bit_error, &bit_count); |
1854 | break; | 1917 | break; |
1918 | case SYS_ISDBT: | ||
1919 | ret = cxd2841er_read_ber_i(priv, &bit_error, &bit_count); | ||
1920 | break; | ||
1855 | case SYS_DVBS: | 1921 | case SYS_DVBS: |
1856 | ret = cxd2841er_mon_read_ber_s(priv, &bit_error, &bit_count); | 1922 | ret = cxd2841er_mon_read_ber_s(priv, &bit_error, &bit_count); |
1857 | break; | 1923 | break; |
@@ -1965,6 +2031,9 @@ static void cxd2841er_read_snr(struct dvb_frontend *fe) | |||
1965 | return; | 2031 | return; |
1966 | } | 2032 | } |
1967 | 2033 | ||
2034 | dev_dbg(&priv->i2c->dev, "%s(): snr=%d\n", | ||
2035 | __func__, (int32_t)tmp); | ||
2036 | |||
1968 | if (!ret) { | 2037 | if (!ret) { |
1969 | p->cnr.stat[0].scale = FE_SCALE_DECIBEL; | 2038 | p->cnr.stat[0].scale = FE_SCALE_DECIBEL; |
1970 | p->cnr.stat[0].svalue = tmp; | 2039 | p->cnr.stat[0].svalue = tmp; |
@@ -1977,7 +2046,7 @@ static void cxd2841er_read_ucblocks(struct dvb_frontend *fe) | |||
1977 | { | 2046 | { |
1978 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 2047 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
1979 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 2048 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
1980 | u32 ucblocks; | 2049 | u32 ucblocks = 0; |
1981 | 2050 | ||
1982 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 2051 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
1983 | switch (p->delivery_system) { | 2052 | switch (p->delivery_system) { |
@@ -1999,7 +2068,7 @@ static void cxd2841er_read_ucblocks(struct dvb_frontend *fe) | |||
1999 | p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 2068 | p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
2000 | return; | 2069 | return; |
2001 | } | 2070 | } |
2002 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 2071 | dev_dbg(&priv->i2c->dev, "%s() ucblocks=%u\n", __func__, ucblocks); |
2003 | 2072 | ||
2004 | p->block_error.stat[0].scale = FE_SCALE_COUNTER; | 2073 | p->block_error.stat[0].scale = FE_SCALE_COUNTER; |
2005 | p->block_error.stat[0].uvalue = ucblocks; | 2074 | p->block_error.stat[0].uvalue = ucblocks; |
@@ -2694,6 +2763,14 @@ static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv, | |||
2694 | u8 b10_b6[3]; | 2763 | u8 b10_b6[3]; |
2695 | u32 iffreq; | 2764 | u32 iffreq; |
2696 | 2765 | ||
2766 | if (bandwidth != 6000000 && | ||
2767 | bandwidth != 7000000 && | ||
2768 | bandwidth != 8000000) { | ||
2769 | dev_info(&priv->i2c->dev, "%s(): unsupported bandwidth %d. Forcing 8Mhz!\n", | ||
2770 | __func__, bandwidth); | ||
2771 | bandwidth = 8000000; | ||
2772 | } | ||
2773 | |||
2697 | dev_dbg(&priv->i2c->dev, "%s() bw=%d\n", __func__, bandwidth); | 2774 | dev_dbg(&priv->i2c->dev, "%s() bw=%d\n", __func__, bandwidth); |
2698 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | 2775 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
2699 | switch (bandwidth) { | 2776 | switch (bandwidth) { |
@@ -3076,6 +3153,7 @@ static int cxd2841er_sleep_tc_to_active_c(struct cxd2841er_priv *priv, | |||
3076 | /* Enable demod clock */ | 3153 | /* Enable demod clock */ |
3077 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01); | 3154 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01); |
3078 | /* Disable RF level monitor */ | 3155 | /* Disable RF level monitor */ |
3156 | cxd2841er_write_reg(priv, I2C_SLVT, 0x59, 0x00); | ||
3079 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00); | 3157 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00); |
3080 | /* Enable ADC clock */ | 3158 | /* Enable ADC clock */ |
3081 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); | 3159 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); |
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index b975da099929..c595adc61c6f 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c | |||
@@ -6448,7 +6448,7 @@ static int get_strength(struct drxk_state *state, u64 *strength) | |||
6448 | return status; | 6448 | return status; |
6449 | 6449 | ||
6450 | /* SCU c.o.c. */ | 6450 | /* SCU c.o.c. */ |
6451 | read16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, &scu_coc); | 6451 | status = read16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, &scu_coc); |
6452 | if (status < 0) | 6452 | if (status < 0) |
6453 | return status; | 6453 | return status; |
6454 | 6454 | ||
diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index 53089e142715..735a96662022 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c | |||
@@ -739,7 +739,7 @@ static int dvb_pll_init(struct dvb_frontend *fe) | |||
739 | return -EINVAL; | 739 | return -EINVAL; |
740 | } | 740 | } |
741 | 741 | ||
742 | static struct dvb_tuner_ops dvb_pll_tuner_ops = { | 742 | static const struct dvb_tuner_ops dvb_pll_tuner_ops = { |
743 | .release = dvb_pll_release, | 743 | .release = dvb_pll_release, |
744 | .sleep = dvb_pll_sleep, | 744 | .sleep = dvb_pll_sleep, |
745 | .init = dvb_pll_init, | 745 | .init = dvb_pll_init, |
diff --git a/drivers/media/dvb-frontends/helene.c b/drivers/media/dvb-frontends/helene.c index 97a8982740a6..dc43c5f6d0ea 100644 --- a/drivers/media/dvb-frontends/helene.c +++ b/drivers/media/dvb-frontends/helene.c | |||
@@ -842,7 +842,7 @@ static int helene_get_frequency(struct dvb_frontend *fe, u32 *frequency) | |||
842 | return 0; | 842 | return 0; |
843 | } | 843 | } |
844 | 844 | ||
845 | static struct dvb_tuner_ops helene_tuner_ops = { | 845 | static const struct dvb_tuner_ops helene_tuner_ops = { |
846 | .info = { | 846 | .info = { |
847 | .name = "Sony HELENE Ter tuner", | 847 | .name = "Sony HELENE Ter tuner", |
848 | .frequency_min = 1000000, | 848 | .frequency_min = 1000000, |
@@ -856,7 +856,7 @@ static struct dvb_tuner_ops helene_tuner_ops = { | |||
856 | .get_frequency = helene_get_frequency, | 856 | .get_frequency = helene_get_frequency, |
857 | }; | 857 | }; |
858 | 858 | ||
859 | static struct dvb_tuner_ops helene_tuner_ops_s = { | 859 | static const struct dvb_tuner_ops helene_tuner_ops_s = { |
860 | .info = { | 860 | .info = { |
861 | .name = "Sony HELENE Sat tuner", | 861 | .name = "Sony HELENE Sat tuner", |
862 | .frequency_min = 500000, | 862 | .frequency_min = 500000, |
@@ -987,8 +987,10 @@ struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe, | |||
987 | if (fe->ops.i2c_gate_ctrl) | 987 | if (fe->ops.i2c_gate_ctrl) |
988 | fe->ops.i2c_gate_ctrl(fe, 1); | 988 | fe->ops.i2c_gate_ctrl(fe, 1); |
989 | 989 | ||
990 | if (helene_x_pon(priv) != 0) | 990 | if (helene_x_pon(priv) != 0) { |
991 | kfree(priv); | ||
991 | return NULL; | 992 | return NULL; |
993 | } | ||
992 | 994 | ||
993 | if (fe->ops.i2c_gate_ctrl) | 995 | if (fe->ops.i2c_gate_ctrl) |
994 | fe->ops.i2c_gate_ctrl(fe, 0); | 996 | fe->ops.i2c_gate_ctrl(fe, 0); |
@@ -1021,8 +1023,10 @@ struct dvb_frontend *helene_attach(struct dvb_frontend *fe, | |||
1021 | if (fe->ops.i2c_gate_ctrl) | 1023 | if (fe->ops.i2c_gate_ctrl) |
1022 | fe->ops.i2c_gate_ctrl(fe, 1); | 1024 | fe->ops.i2c_gate_ctrl(fe, 1); |
1023 | 1025 | ||
1024 | if (helene_x_pon(priv) != 0) | 1026 | if (helene_x_pon(priv) != 0) { |
1027 | kfree(priv); | ||
1025 | return NULL; | 1028 | return NULL; |
1029 | } | ||
1026 | 1030 | ||
1027 | if (fe->ops.i2c_gate_ctrl) | 1031 | if (fe->ops.i2c_gate_ctrl) |
1028 | fe->ops.i2c_gate_ctrl(fe, 0); | 1032 | fe->ops.i2c_gate_ctrl(fe, 0); |
diff --git a/drivers/media/dvb-frontends/horus3a.c b/drivers/media/dvb-frontends/horus3a.c index a98bca5270d9..0c089b5986a1 100644 --- a/drivers/media/dvb-frontends/horus3a.c +++ b/drivers/media/dvb-frontends/horus3a.c | |||
@@ -326,7 +326,7 @@ static int horus3a_get_frequency(struct dvb_frontend *fe, u32 *frequency) | |||
326 | return 0; | 326 | return 0; |
327 | } | 327 | } |
328 | 328 | ||
329 | static struct dvb_tuner_ops horus3a_tuner_ops = { | 329 | static const struct dvb_tuner_ops horus3a_tuner_ops = { |
330 | .info = { | 330 | .info = { |
331 | .name = "Sony Horus3a", | 331 | .name = "Sony Horus3a", |
332 | .frequency_min = 950000, | 332 | .frequency_min = 950000, |
diff --git a/drivers/media/dvb-frontends/ix2505v.c b/drivers/media/dvb-frontends/ix2505v.c index 0e3387e00952..2826bbb36b73 100644 --- a/drivers/media/dvb-frontends/ix2505v.c +++ b/drivers/media/dvb-frontends/ix2505v.c | |||
@@ -258,7 +258,7 @@ static int ix2505v_get_frequency(struct dvb_frontend *fe, u32 *frequency) | |||
258 | return 0; | 258 | return 0; |
259 | } | 259 | } |
260 | 260 | ||
261 | static struct dvb_tuner_ops ix2505v_tuner_ops = { | 261 | static const struct dvb_tuner_ops ix2505v_tuner_ops = { |
262 | .info = { | 262 | .info = { |
263 | .name = "Sharp IX2505V (B0017)", | 263 | .name = "Sharp IX2505V (B0017)", |
264 | .frequency_min = 950000, | 264 | .frequency_min = 950000, |
diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 179c26e5eb4e..0ca4e810e9d8 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c | |||
@@ -731,7 +731,7 @@ static int lgdt3306a_set_if(struct lgdt3306a_state *state, | |||
731 | 731 | ||
732 | switch (if_freq_khz) { | 732 | switch (if_freq_khz) { |
733 | default: | 733 | default: |
734 | pr_warn("IF=%d KHz is not supportted, 3250 assumed\n", | 734 | pr_warn("IF=%d KHz is not supported, 3250 assumed\n", |
735 | if_freq_khz); | 735 | if_freq_khz); |
736 | /* fallthrough */ | 736 | /* fallthrough */ |
737 | case 3250: /* 3.25Mhz */ | 737 | case 3250: /* 3.25Mhz */ |
@@ -1737,24 +1737,16 @@ static int lgdt3306a_get_tune_settings(struct dvb_frontend *fe, | |||
1737 | static int lgdt3306a_search(struct dvb_frontend *fe) | 1737 | static int lgdt3306a_search(struct dvb_frontend *fe) |
1738 | { | 1738 | { |
1739 | enum fe_status status = 0; | 1739 | enum fe_status status = 0; |
1740 | int i, ret; | 1740 | int ret; |
1741 | 1741 | ||
1742 | /* set frontend */ | 1742 | /* set frontend */ |
1743 | ret = lgdt3306a_set_parameters(fe); | 1743 | ret = lgdt3306a_set_parameters(fe); |
1744 | if (ret) | 1744 | if (ret) |
1745 | goto error; | 1745 | goto error; |
1746 | 1746 | ||
1747 | /* wait frontend lock */ | 1747 | ret = lgdt3306a_read_status(fe, &status); |
1748 | for (i = 20; i > 0; i--) { | 1748 | if (ret) |
1749 | dbg_info(": loop=%d\n", i); | 1749 | goto error; |
1750 | msleep(50); | ||
1751 | ret = lgdt3306a_read_status(fe, &status); | ||
1752 | if (ret) | ||
1753 | goto error; | ||
1754 | |||
1755 | if (status & FE_HAS_LOCK) | ||
1756 | break; | ||
1757 | } | ||
1758 | 1750 | ||
1759 | /* check if we have a valid signal */ | 1751 | /* check if we have a valid signal */ |
1760 | if (status & FE_HAS_LOCK) | 1752 | if (status & FE_HAS_LOCK) |
diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 41325328a22e..fe79358b035e 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c | |||
@@ -71,25 +71,27 @@ static struct regdata mb86a20s_init1[] = { | |||
71 | }; | 71 | }; |
72 | 72 | ||
73 | static struct regdata mb86a20s_init2[] = { | 73 | static struct regdata mb86a20s_init2[] = { |
74 | { 0x28, 0x22 }, { 0x29, 0x00 }, { 0x2a, 0x1f }, { 0x2b, 0xf0 }, | 74 | { 0x50, 0xd1 }, { 0x51, 0x22 }, |
75 | { 0x39, 0x01 }, | ||
76 | { 0x71, 0x00 }, | ||
75 | { 0x3b, 0x21 }, | 77 | { 0x3b, 0x21 }, |
76 | { 0x3c, 0x38 }, | 78 | { 0x3c, 0x3a }, |
77 | { 0x01, 0x0d }, | 79 | { 0x01, 0x0d }, |
78 | { 0x04, 0x08 }, { 0x05, 0x03 }, | 80 | { 0x04, 0x08 }, { 0x05, 0x05 }, |
79 | { 0x04, 0x0e }, { 0x05, 0x00 }, | 81 | { 0x04, 0x0e }, { 0x05, 0x00 }, |
80 | { 0x04, 0x0f }, { 0x05, 0x37 }, | 82 | { 0x04, 0x0f }, { 0x05, 0x14 }, |
81 | { 0x04, 0x0b }, { 0x05, 0x78 }, | 83 | { 0x04, 0x0b }, { 0x05, 0x8c }, |
82 | { 0x04, 0x00 }, { 0x05, 0x00 }, | 84 | { 0x04, 0x00 }, { 0x05, 0x00 }, |
83 | { 0x04, 0x01 }, { 0x05, 0x1e }, | 85 | { 0x04, 0x01 }, { 0x05, 0x07 }, |
84 | { 0x04, 0x02 }, { 0x05, 0x07 }, | 86 | { 0x04, 0x02 }, { 0x05, 0x0f }, |
85 | { 0x04, 0x03 }, { 0x05, 0xd0 }, | 87 | { 0x04, 0x03 }, { 0x05, 0xa0 }, |
86 | { 0x04, 0x09 }, { 0x05, 0x00 }, | 88 | { 0x04, 0x09 }, { 0x05, 0x00 }, |
87 | { 0x04, 0x0a }, { 0x05, 0xff }, | 89 | { 0x04, 0x0a }, { 0x05, 0xff }, |
88 | { 0x04, 0x27 }, { 0x05, 0x00 }, | 90 | { 0x04, 0x27 }, { 0x05, 0x64 }, |
89 | { 0x04, 0x28 }, { 0x05, 0x00 }, | 91 | { 0x04, 0x28 }, { 0x05, 0x00 }, |
90 | { 0x04, 0x1e }, { 0x05, 0x00 }, | 92 | { 0x04, 0x1e }, { 0x05, 0xff }, |
91 | { 0x04, 0x29 }, { 0x05, 0x64 }, | 93 | { 0x04, 0x29 }, { 0x05, 0x0a }, |
92 | { 0x04, 0x32 }, { 0x05, 0x02 }, | 94 | { 0x04, 0x32 }, { 0x05, 0x0a }, |
93 | { 0x04, 0x14 }, { 0x05, 0x02 }, | 95 | { 0x04, 0x14 }, { 0x05, 0x02 }, |
94 | { 0x04, 0x04 }, { 0x05, 0x00 }, | 96 | { 0x04, 0x04 }, { 0x05, 0x00 }, |
95 | { 0x04, 0x05 }, { 0x05, 0x22 }, | 97 | { 0x04, 0x05 }, { 0x05, 0x22 }, |
@@ -97,8 +99,6 @@ static struct regdata mb86a20s_init2[] = { | |||
97 | { 0x04, 0x07 }, { 0x05, 0xd8 }, | 99 | { 0x04, 0x07 }, { 0x05, 0xd8 }, |
98 | { 0x04, 0x12 }, { 0x05, 0x00 }, | 100 | { 0x04, 0x12 }, { 0x05, 0x00 }, |
99 | { 0x04, 0x13 }, { 0x05, 0xff }, | 101 | { 0x04, 0x13 }, { 0x05, 0xff }, |
100 | { 0x04, 0x15 }, { 0x05, 0x4e }, | ||
101 | { 0x04, 0x16 }, { 0x05, 0x20 }, | ||
102 | 102 | ||
103 | /* | 103 | /* |
104 | * On this demod, when the bit count reaches the count below, | 104 | * On this demod, when the bit count reaches the count below, |
@@ -152,42 +152,36 @@ static struct regdata mb86a20s_init2[] = { | |||
152 | { 0x50, 0x51 }, { 0x51, 0x04 }, /* MER symbol 4 */ | 152 | { 0x50, 0x51 }, { 0x51, 0x04 }, /* MER symbol 4 */ |
153 | { 0x45, 0x04 }, /* CN symbol 4 */ | 153 | { 0x45, 0x04 }, /* CN symbol 4 */ |
154 | { 0x48, 0x04 }, /* CN manual mode */ | 154 | { 0x48, 0x04 }, /* CN manual mode */ |
155 | 155 | { 0x50, 0xd5 }, { 0x51, 0x01 }, | |
156 | { 0x50, 0xd6 }, { 0x51, 0x1f }, | 156 | { 0x50, 0xd6 }, { 0x51, 0x1f }, |
157 | { 0x50, 0xd2 }, { 0x51, 0x03 }, | 157 | { 0x50, 0xd2 }, { 0x51, 0x03 }, |
158 | { 0x50, 0xd7 }, { 0x51, 0xbf }, | 158 | { 0x50, 0xd7 }, { 0x51, 0x3f }, |
159 | { 0x28, 0x74 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0xff }, | ||
160 | { 0x28, 0x46 }, { 0x29, 0x00 }, { 0x2a, 0x1a }, { 0x2b, 0x0c }, | ||
161 | |||
162 | { 0x04, 0x40 }, { 0x05, 0x00 }, | ||
163 | { 0x28, 0x00 }, { 0x2b, 0x08 }, | ||
164 | { 0x28, 0x05 }, { 0x2b, 0x00 }, | ||
165 | { 0x1c, 0x01 }, | 159 | { 0x1c, 0x01 }, |
166 | { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x1f }, | 160 | { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 }, |
167 | { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x18 }, | 161 | { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d }, |
168 | { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x12 }, | 162 | { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 }, |
169 | { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x30 }, | 163 | { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 }, |
170 | { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x37 }, | 164 | { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 }, |
171 | { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 }, | 165 | { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 }, |
172 | { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x09 }, | 166 | { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 }, |
173 | { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x06 }, | 167 | { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 }, |
174 | { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x7b }, | 168 | { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e }, |
175 | { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x76 }, | 169 | { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e }, |
176 | { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x7d }, | 170 | { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 }, |
177 | { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x08 }, | 171 | { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f }, |
178 | { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0b }, | 172 | { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 }, |
179 | { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 }, | 173 | { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 }, |
180 | { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xf2 }, | 174 | { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe }, |
181 | { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xf3 }, | 175 | { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 }, |
182 | { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x05 }, | 176 | { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee }, |
183 | { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 }, | 177 | { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 }, |
184 | { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f }, | 178 | { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f }, |
185 | { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xef }, | 179 | { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 }, |
186 | { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xd8 }, | 180 | { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 }, |
187 | { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xf1 }, | 181 | { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a }, |
188 | { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x3d }, | 182 | { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc }, |
189 | { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x94 }, | 183 | { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba }, |
190 | { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0xba }, | 184 | { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 }, |
191 | { 0x50, 0x1e }, { 0x51, 0x5d }, | 185 | { 0x50, 0x1e }, { 0x51, 0x5d }, |
192 | { 0x50, 0x22 }, { 0x51, 0x00 }, | 186 | { 0x50, 0x22 }, { 0x51, 0x00 }, |
193 | { 0x50, 0x23 }, { 0x51, 0xc8 }, | 187 | { 0x50, 0x23 }, { 0x51, 0xc8 }, |
@@ -196,9 +190,7 @@ static struct regdata mb86a20s_init2[] = { | |||
196 | { 0x50, 0x26 }, { 0x51, 0x00 }, | 190 | { 0x50, 0x26 }, { 0x51, 0x00 }, |
197 | { 0x50, 0x27 }, { 0x51, 0xc3 }, | 191 | { 0x50, 0x27 }, { 0x51, 0xc3 }, |
198 | { 0x50, 0x39 }, { 0x51, 0x02 }, | 192 | { 0x50, 0x39 }, { 0x51, 0x02 }, |
199 | { 0xec, 0x0f }, | 193 | { 0x50, 0xd5 }, { 0x51, 0x01 }, |
200 | { 0xeb, 0x1f }, | ||
201 | { 0x28, 0x6a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 }, | ||
202 | { 0xd0, 0x00 }, | 194 | { 0xd0, 0x00 }, |
203 | }; | 195 | }; |
204 | 196 | ||
@@ -318,7 +310,11 @@ static int mb86a20s_read_status(struct dvb_frontend *fe, enum fe_status *status) | |||
318 | if (val >= 7) | 310 | if (val >= 7) |
319 | *status |= FE_HAS_SYNC; | 311 | *status |= FE_HAS_SYNC; |
320 | 312 | ||
321 | if (val >= 8) /* Maybe 9? */ | 313 | /* |
314 | * Actually, on state S8, it starts receiving TS, but the TS | ||
315 | * output is only on normal state after the transition to S9. | ||
316 | */ | ||
317 | if (val >= 9) | ||
322 | *status |= FE_HAS_LOCK; | 318 | *status |= FE_HAS_LOCK; |
323 | 319 | ||
324 | dev_dbg(&state->i2c->dev, "%s: Status = 0x%02x (state = %d)\n", | 320 | dev_dbg(&state->i2c->dev, "%s: Status = 0x%02x (state = %d)\n", |
@@ -2058,6 +2054,11 @@ static void mb86a20s_release(struct dvb_frontend *fe) | |||
2058 | kfree(state); | 2054 | kfree(state); |
2059 | } | 2055 | } |
2060 | 2056 | ||
2057 | static int mb86a20s_get_frontend_algo(struct dvb_frontend *fe) | ||
2058 | { | ||
2059 | return DVBFE_ALGO_HW; | ||
2060 | } | ||
2061 | |||
2061 | static struct dvb_frontend_ops mb86a20s_ops; | 2062 | static struct dvb_frontend_ops mb86a20s_ops; |
2062 | 2063 | ||
2063 | struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, | 2064 | struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, |
@@ -2130,6 +2131,7 @@ static struct dvb_frontend_ops mb86a20s_ops = { | |||
2130 | .read_status = mb86a20s_read_status_and_stats, | 2131 | .read_status = mb86a20s_read_status_and_stats, |
2131 | .read_signal_strength = mb86a20s_read_signal_strength_from_cache, | 2132 | .read_signal_strength = mb86a20s_read_signal_strength_from_cache, |
2132 | .tune = mb86a20s_tune, | 2133 | .tune = mb86a20s_tune, |
2134 | .get_frontend_algo = mb86a20s_get_frontend_algo, | ||
2133 | }; | 2135 | }; |
2134 | 2136 | ||
2135 | MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware"); | 2137 | MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware"); |
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 8bf716a8ea58..78669ea68c61 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/string.h> | 25 | #include <linux/string.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/firmware.h> | 27 | #include <linux/firmware.h> |
28 | #include <linux/regmap.h> | ||
28 | 29 | ||
29 | #include "dvb_frontend.h" | 30 | #include "dvb_frontend.h" |
30 | #include "dvb_math.h" | 31 | #include "dvb_math.h" |
@@ -40,7 +41,9 @@ | |||
40 | */ | 41 | */ |
41 | 42 | ||
42 | struct si2165_state { | 43 | struct si2165_state { |
43 | struct i2c_adapter *i2c; | 44 | struct i2c_client *client; |
45 | |||
46 | struct regmap *regmap; | ||
44 | 47 | ||
45 | struct dvb_frontend fe; | 48 | struct dvb_frontend fe; |
46 | 49 | ||
@@ -108,61 +111,27 @@ static int si2165_write(struct si2165_state *state, const u16 reg, | |||
108 | const u8 *src, const int count) | 111 | const u8 *src, const int count) |
109 | { | 112 | { |
110 | int ret; | 113 | int ret; |
111 | struct i2c_msg msg; | ||
112 | u8 buf[2 + 4]; /* write a maximum of 4 bytes of data */ | ||
113 | |||
114 | if (count + 2 > sizeof(buf)) { | ||
115 | dev_warn(&state->i2c->dev, | ||
116 | "%s: i2c wr reg=%04x: count=%d is too big!\n", | ||
117 | KBUILD_MODNAME, reg, count); | ||
118 | return -EINVAL; | ||
119 | } | ||
120 | buf[0] = reg >> 8; | ||
121 | buf[1] = reg & 0xff; | ||
122 | memcpy(buf + 2, src, count); | ||
123 | |||
124 | msg.addr = state->config.i2c_addr; | ||
125 | msg.flags = 0; | ||
126 | msg.buf = buf; | ||
127 | msg.len = count + 2; | ||
128 | 114 | ||
129 | if (debug & DEBUG_I2C_WRITE) | 115 | if (debug & DEBUG_I2C_WRITE) |
130 | deb_i2c_write("reg: 0x%04x, data: %*ph\n", reg, count, src); | 116 | deb_i2c_write("reg: 0x%04x, data: %*ph\n", reg, count, src); |
131 | 117 | ||
132 | ret = i2c_transfer(state->i2c, &msg, 1); | 118 | ret = regmap_bulk_write(state->regmap, reg, src, count); |
133 | 119 | ||
134 | if (ret != 1) { | 120 | if (ret) |
135 | dev_err(&state->i2c->dev, "%s: ret == %d\n", __func__, ret); | 121 | dev_err(&state->client->dev, "%s: ret == %d\n", __func__, ret); |
136 | if (ret < 0) | ||
137 | return ret; | ||
138 | else | ||
139 | return -EREMOTEIO; | ||
140 | } | ||
141 | 122 | ||
142 | return 0; | 123 | return ret; |
143 | } | 124 | } |
144 | 125 | ||
145 | static int si2165_read(struct si2165_state *state, | 126 | static int si2165_read(struct si2165_state *state, |
146 | const u16 reg, u8 *val, const int count) | 127 | const u16 reg, u8 *val, const int count) |
147 | { | 128 | { |
148 | int ret; | 129 | int ret = regmap_bulk_read(state->regmap, reg, val, count); |
149 | u8 reg_buf[] = { reg >> 8, reg & 0xff }; | ||
150 | struct i2c_msg msg[] = { | ||
151 | { .addr = state->config.i2c_addr, | ||
152 | .flags = 0, .buf = reg_buf, .len = 2 }, | ||
153 | { .addr = state->config.i2c_addr, | ||
154 | .flags = I2C_M_RD, .buf = val, .len = count }, | ||
155 | }; | ||
156 | |||
157 | ret = i2c_transfer(state->i2c, msg, 2); | ||
158 | 130 | ||
159 | if (ret != 2) { | 131 | if (ret) { |
160 | dev_err(&state->i2c->dev, "%s: error (addr %02x reg %04x error (ret == %i)\n", | 132 | dev_err(&state->client->dev, "%s: error (addr %02x reg %04x error (ret == %i)\n", |
161 | __func__, state->config.i2c_addr, reg, ret); | 133 | __func__, state->config.i2c_addr, reg, ret); |
162 | if (ret < 0) | 134 | return ret; |
163 | return ret; | ||
164 | else | ||
165 | return -EREMOTEIO; | ||
166 | } | 135 | } |
167 | 136 | ||
168 | if (debug & DEBUG_I2C_READ) | 137 | if (debug & DEBUG_I2C_READ) |
@@ -174,9 +143,9 @@ static int si2165_read(struct si2165_state *state, | |||
174 | static int si2165_readreg8(struct si2165_state *state, | 143 | static int si2165_readreg8(struct si2165_state *state, |
175 | const u16 reg, u8 *val) | 144 | const u16 reg, u8 *val) |
176 | { | 145 | { |
177 | int ret; | 146 | unsigned int val_tmp; |
178 | 147 | int ret = regmap_read(state->regmap, reg, &val_tmp); | |
179 | ret = si2165_read(state, reg, val, 1); | 148 | *val = (u8)val_tmp; |
180 | deb_readreg("R(0x%04x)=0x%02x\n", reg, *val); | 149 | deb_readreg("R(0x%04x)=0x%02x\n", reg, *val); |
181 | return ret; | 150 | return ret; |
182 | } | 151 | } |
@@ -194,7 +163,7 @@ static int si2165_readreg16(struct si2165_state *state, | |||
194 | 163 | ||
195 | static int si2165_writereg8(struct si2165_state *state, const u16 reg, u8 val) | 164 | static int si2165_writereg8(struct si2165_state *state, const u16 reg, u8 val) |
196 | { | 165 | { |
197 | return si2165_write(state, reg, &val, 1); | 166 | return regmap_write(state->regmap, reg, val); |
198 | } | 167 | } |
199 | 168 | ||
200 | static int si2165_writereg16(struct si2165_state *state, const u16 reg, u16 val) | 169 | static int si2165_writereg16(struct si2165_state *state, const u16 reg, u16 val) |
@@ -345,7 +314,7 @@ static int si2165_wait_init_done(struct si2165_state *state) | |||
345 | return 0; | 314 | return 0; |
346 | usleep_range(1000, 50000); | 315 | usleep_range(1000, 50000); |
347 | } | 316 | } |
348 | dev_err(&state->i2c->dev, "%s: init_done was not set\n", | 317 | dev_err(&state->client->dev, "%s: init_done was not set\n", |
349 | KBUILD_MODNAME); | 318 | KBUILD_MODNAME); |
350 | return ret; | 319 | return ret; |
351 | } | 320 | } |
@@ -374,14 +343,14 @@ static int si2165_upload_firmware_block(struct si2165_state *state, | |||
374 | wordcount = data[offset]; | 343 | wordcount = data[offset]; |
375 | if (wordcount < 1 || data[offset+1] || | 344 | if (wordcount < 1 || data[offset+1] || |
376 | data[offset+2] || data[offset+3]) { | 345 | data[offset+2] || data[offset+3]) { |
377 | dev_warn(&state->i2c->dev, | 346 | dev_warn(&state->client->dev, |
378 | "%s: bad fw data[0..3] = %*ph\n", | 347 | "%s: bad fw data[0..3] = %*ph\n", |
379 | KBUILD_MODNAME, 4, data); | 348 | KBUILD_MODNAME, 4, data); |
380 | return -EINVAL; | 349 | return -EINVAL; |
381 | } | 350 | } |
382 | 351 | ||
383 | if (offset + 8 + wordcount * 4 > len) { | 352 | if (offset + 8 + wordcount * 4 > len) { |
384 | dev_warn(&state->i2c->dev, | 353 | dev_warn(&state->client->dev, |
385 | "%s: len is too small for block len=%d, wordcount=%d\n", | 354 | "%s: len is too small for block len=%d, wordcount=%d\n", |
386 | KBUILD_MODNAME, len, wordcount); | 355 | KBUILD_MODNAME, len, wordcount); |
387 | return -EINVAL; | 356 | return -EINVAL; |
@@ -444,15 +413,15 @@ static int si2165_upload_firmware(struct si2165_state *state) | |||
444 | fw_file = SI2165_FIRMWARE_REV_D; | 413 | fw_file = SI2165_FIRMWARE_REV_D; |
445 | break; | 414 | break; |
446 | default: | 415 | default: |
447 | dev_info(&state->i2c->dev, "%s: no firmware file for revision=%d\n", | 416 | dev_info(&state->client->dev, "%s: no firmware file for revision=%d\n", |
448 | KBUILD_MODNAME, state->chip_revcode); | 417 | KBUILD_MODNAME, state->chip_revcode); |
449 | return 0; | 418 | return 0; |
450 | } | 419 | } |
451 | 420 | ||
452 | /* request the firmware, this will block and timeout */ | 421 | /* request the firmware, this will block and timeout */ |
453 | ret = request_firmware(&fw, fw_file, state->i2c->dev.parent); | 422 | ret = request_firmware(&fw, fw_file, &state->client->dev); |
454 | if (ret) { | 423 | if (ret) { |
455 | dev_warn(&state->i2c->dev, "%s: firmware file '%s' not found\n", | 424 | dev_warn(&state->client->dev, "%s: firmware file '%s' not found\n", |
456 | KBUILD_MODNAME, fw_file); | 425 | KBUILD_MODNAME, fw_file); |
457 | goto error; | 426 | goto error; |
458 | } | 427 | } |
@@ -460,11 +429,11 @@ static int si2165_upload_firmware(struct si2165_state *state) | |||
460 | data = fw->data; | 429 | data = fw->data; |
461 | len = fw->size; | 430 | len = fw->size; |
462 | 431 | ||
463 | dev_info(&state->i2c->dev, "%s: downloading firmware from file '%s' size=%d\n", | 432 | dev_info(&state->client->dev, "%s: downloading firmware from file '%s' size=%d\n", |
464 | KBUILD_MODNAME, fw_file, len); | 433 | KBUILD_MODNAME, fw_file, len); |
465 | 434 | ||
466 | if (len % 4 != 0) { | 435 | if (len % 4 != 0) { |
467 | dev_warn(&state->i2c->dev, "%s: firmware size is not multiple of 4\n", | 436 | dev_warn(&state->client->dev, "%s: firmware size is not multiple of 4\n", |
468 | KBUILD_MODNAME); | 437 | KBUILD_MODNAME); |
469 | ret = -EINVAL; | 438 | ret = -EINVAL; |
470 | goto error; | 439 | goto error; |
@@ -472,14 +441,14 @@ static int si2165_upload_firmware(struct si2165_state *state) | |||
472 | 441 | ||
473 | /* check header (8 bytes) */ | 442 | /* check header (8 bytes) */ |
474 | if (len < 8) { | 443 | if (len < 8) { |
475 | dev_warn(&state->i2c->dev, "%s: firmware header is missing\n", | 444 | dev_warn(&state->client->dev, "%s: firmware header is missing\n", |
476 | KBUILD_MODNAME); | 445 | KBUILD_MODNAME); |
477 | ret = -EINVAL; | 446 | ret = -EINVAL; |
478 | goto error; | 447 | goto error; |
479 | } | 448 | } |
480 | 449 | ||
481 | if (data[0] != 1 || data[1] != 0) { | 450 | if (data[0] != 1 || data[1] != 0) { |
482 | dev_warn(&state->i2c->dev, "%s: firmware file version is wrong\n", | 451 | dev_warn(&state->client->dev, "%s: firmware file version is wrong\n", |
483 | KBUILD_MODNAME); | 452 | KBUILD_MODNAME); |
484 | ret = -EINVAL; | 453 | ret = -EINVAL; |
485 | goto error; | 454 | goto error; |
@@ -517,7 +486,7 @@ static int si2165_upload_firmware(struct si2165_state *state) | |||
517 | /* start right after the header */ | 486 | /* start right after the header */ |
518 | offset = 8; | 487 | offset = 8; |
519 | 488 | ||
520 | dev_info(&state->i2c->dev, "%s: si2165_upload_firmware extracted patch_version=0x%02x, block_count=0x%02x, crc_expected=0x%04x\n", | 489 | dev_info(&state->client->dev, "%s: si2165_upload_firmware extracted patch_version=0x%02x, block_count=0x%02x, crc_expected=0x%04x\n", |
521 | KBUILD_MODNAME, patch_version, block_count, crc_expected); | 490 | KBUILD_MODNAME, patch_version, block_count, crc_expected); |
522 | 491 | ||
523 | ret = si2165_upload_firmware_block(state, data, len, &offset, 1); | 492 | ret = si2165_upload_firmware_block(state, data, len, &offset, 1); |
@@ -536,7 +505,7 @@ static int si2165_upload_firmware(struct si2165_state *state) | |||
536 | ret = si2165_upload_firmware_block(state, data, len, | 505 | ret = si2165_upload_firmware_block(state, data, len, |
537 | &offset, block_count); | 506 | &offset, block_count); |
538 | if (ret < 0) { | 507 | if (ret < 0) { |
539 | dev_err(&state->i2c->dev, | 508 | dev_err(&state->client->dev, |
540 | "%s: firmware could not be uploaded\n", | 509 | "%s: firmware could not be uploaded\n", |
541 | KBUILD_MODNAME); | 510 | KBUILD_MODNAME); |
542 | goto error; | 511 | goto error; |
@@ -548,7 +517,7 @@ static int si2165_upload_firmware(struct si2165_state *state) | |||
548 | goto error; | 517 | goto error; |
549 | 518 | ||
550 | if (val16 != crc_expected) { | 519 | if (val16 != crc_expected) { |
551 | dev_err(&state->i2c->dev, | 520 | dev_err(&state->client->dev, |
552 | "%s: firmware crc mismatch %04x != %04x\n", | 521 | "%s: firmware crc mismatch %04x != %04x\n", |
553 | KBUILD_MODNAME, val16, crc_expected); | 522 | KBUILD_MODNAME, val16, crc_expected); |
554 | ret = -EINVAL; | 523 | ret = -EINVAL; |
@@ -560,7 +529,7 @@ static int si2165_upload_firmware(struct si2165_state *state) | |||
560 | goto error; | 529 | goto error; |
561 | 530 | ||
562 | if (len != offset) { | 531 | if (len != offset) { |
563 | dev_err(&state->i2c->dev, | 532 | dev_err(&state->client->dev, |
564 | "%s: firmware len mismatch %04x != %04x\n", | 533 | "%s: firmware len mismatch %04x != %04x\n", |
565 | KBUILD_MODNAME, len, offset); | 534 | KBUILD_MODNAME, len, offset); |
566 | ret = -EINVAL; | 535 | ret = -EINVAL; |
@@ -577,7 +546,7 @@ static int si2165_upload_firmware(struct si2165_state *state) | |||
577 | if (ret < 0) | 546 | if (ret < 0) |
578 | goto error; | 547 | goto error; |
579 | 548 | ||
580 | dev_info(&state->i2c->dev, "%s: fw load finished\n", KBUILD_MODNAME); | 549 | dev_info(&state->client->dev, "%s: fw load finished\n", KBUILD_MODNAME); |
581 | 550 | ||
582 | ret = 0; | 551 | ret = 0; |
583 | state->firmware_loaded = true; | 552 | state->firmware_loaded = true; |
@@ -611,7 +580,7 @@ static int si2165_init(struct dvb_frontend *fe) | |||
611 | if (ret < 0) | 580 | if (ret < 0) |
612 | goto error; | 581 | goto error; |
613 | if (val != state->config.chip_mode) { | 582 | if (val != state->config.chip_mode) { |
614 | dev_err(&state->i2c->dev, "%s: could not set chip_mode\n", | 583 | dev_err(&state->client->dev, "%s: could not set chip_mode\n", |
615 | KBUILD_MODNAME); | 584 | KBUILD_MODNAME); |
616 | return -EINVAL; | 585 | return -EINVAL; |
617 | } | 586 | } |
@@ -751,6 +720,9 @@ static int si2165_set_oversamp(struct si2165_state *state, u32 dvb_rate) | |||
751 | u64 oversamp; | 720 | u64 oversamp; |
752 | u32 reg_value; | 721 | u32 reg_value; |
753 | 722 | ||
723 | if (!dvb_rate) | ||
724 | return -EINVAL; | ||
725 | |||
754 | oversamp = si2165_get_fe_clk(state); | 726 | oversamp = si2165_get_fe_clk(state); |
755 | oversamp <<= 23; | 727 | oversamp <<= 23; |
756 | do_div(oversamp, dvb_rate); | 728 | do_div(oversamp, dvb_rate); |
@@ -769,12 +741,15 @@ static int si2165_set_if_freq_shift(struct si2165_state *state) | |||
769 | u32 IF = 0; | 741 | u32 IF = 0; |
770 | 742 | ||
771 | if (!fe->ops.tuner_ops.get_if_frequency) { | 743 | if (!fe->ops.tuner_ops.get_if_frequency) { |
772 | dev_err(&state->i2c->dev, | 744 | dev_err(&state->client->dev, |
773 | "%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n", | 745 | "%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n", |
774 | KBUILD_MODNAME); | 746 | KBUILD_MODNAME); |
775 | return -EINVAL; | 747 | return -EINVAL; |
776 | } | 748 | } |
777 | 749 | ||
750 | if (!fe_clk) | ||
751 | return -EINVAL; | ||
752 | |||
778 | fe->ops.tuner_ops.get_if_frequency(fe, &IF); | 753 | fe->ops.tuner_ops.get_if_frequency(fe, &IF); |
779 | if_freq_shift = IF; | 754 | if_freq_shift = IF; |
780 | if_freq_shift <<= 29; | 755 | if_freq_shift <<= 29; |
@@ -1003,14 +978,6 @@ static int si2165_set_frontend(struct dvb_frontend *fe) | |||
1003 | return 0; | 978 | return 0; |
1004 | } | 979 | } |
1005 | 980 | ||
1006 | static void si2165_release(struct dvb_frontend *fe) | ||
1007 | { | ||
1008 | struct si2165_state *state = fe->demodulator_priv; | ||
1009 | |||
1010 | dprintk("%s: called\n", __func__); | ||
1011 | kfree(state); | ||
1012 | } | ||
1013 | |||
1014 | static struct dvb_frontend_ops si2165_ops = { | 981 | static struct dvb_frontend_ops si2165_ops = { |
1015 | .info = { | 982 | .info = { |
1016 | .name = "Silicon Labs ", | 983 | .name = "Silicon Labs ", |
@@ -1046,67 +1013,83 @@ static struct dvb_frontend_ops si2165_ops = { | |||
1046 | 1013 | ||
1047 | .set_frontend = si2165_set_frontend, | 1014 | .set_frontend = si2165_set_frontend, |
1048 | .read_status = si2165_read_status, | 1015 | .read_status = si2165_read_status, |
1049 | |||
1050 | .release = si2165_release, | ||
1051 | }; | 1016 | }; |
1052 | 1017 | ||
1053 | struct dvb_frontend *si2165_attach(const struct si2165_config *config, | 1018 | static int si2165_probe(struct i2c_client *client, |
1054 | struct i2c_adapter *i2c) | 1019 | const struct i2c_device_id *id) |
1055 | { | 1020 | { |
1056 | struct si2165_state *state = NULL; | 1021 | struct si2165_state *state = NULL; |
1022 | struct si2165_platform_data *pdata = client->dev.platform_data; | ||
1057 | int n; | 1023 | int n; |
1058 | int io_ret; | 1024 | int ret = 0; |
1059 | u8 val; | 1025 | u8 val; |
1060 | char rev_char; | 1026 | char rev_char; |
1061 | const char *chip_name; | 1027 | const char *chip_name; |
1062 | 1028 | static const struct regmap_config regmap_config = { | |
1063 | if (config == NULL || i2c == NULL) | 1029 | .reg_bits = 16, |
1064 | goto error; | 1030 | .val_bits = 8, |
1031 | .max_register = 0x08ff, | ||
1032 | }; | ||
1065 | 1033 | ||
1066 | /* allocate memory for the internal state */ | 1034 | /* allocate memory for the internal state */ |
1067 | state = kzalloc(sizeof(struct si2165_state), GFP_KERNEL); | 1035 | state = kzalloc(sizeof(struct si2165_state), GFP_KERNEL); |
1068 | if (state == NULL) | 1036 | if (state == NULL) { |
1037 | ret = -ENOMEM; | ||
1069 | goto error; | 1038 | goto error; |
1039 | } | ||
1040 | |||
1041 | /* create regmap */ | ||
1042 | state->regmap = devm_regmap_init_i2c(client, ®map_config); | ||
1043 | if (IS_ERR(state->regmap)) { | ||
1044 | ret = PTR_ERR(state->regmap); | ||
1045 | goto error; | ||
1046 | } | ||
1070 | 1047 | ||
1071 | /* setup the state */ | 1048 | /* setup the state */ |
1072 | state->i2c = i2c; | 1049 | state->client = client; |
1073 | state->config = *config; | 1050 | state->config.i2c_addr = client->addr; |
1051 | state->config.chip_mode = pdata->chip_mode; | ||
1052 | state->config.ref_freq_Hz = pdata->ref_freq_Hz; | ||
1053 | state->config.inversion = pdata->inversion; | ||
1074 | 1054 | ||
1075 | if (state->config.ref_freq_Hz < 4000000 | 1055 | if (state->config.ref_freq_Hz < 4000000 |
1076 | || state->config.ref_freq_Hz > 27000000) { | 1056 | || state->config.ref_freq_Hz > 27000000) { |
1077 | dev_err(&state->i2c->dev, "%s: ref_freq of %d Hz not supported by this driver\n", | 1057 | dev_err(&state->client->dev, "%s: ref_freq of %d Hz not supported by this driver\n", |
1078 | KBUILD_MODNAME, state->config.ref_freq_Hz); | 1058 | KBUILD_MODNAME, state->config.ref_freq_Hz); |
1059 | ret = -EINVAL; | ||
1079 | goto error; | 1060 | goto error; |
1080 | } | 1061 | } |
1081 | 1062 | ||
1082 | /* create dvb_frontend */ | 1063 | /* create dvb_frontend */ |
1083 | memcpy(&state->fe.ops, &si2165_ops, | 1064 | memcpy(&state->fe.ops, &si2165_ops, |
1084 | sizeof(struct dvb_frontend_ops)); | 1065 | sizeof(struct dvb_frontend_ops)); |
1066 | state->fe.ops.release = NULL; | ||
1085 | state->fe.demodulator_priv = state; | 1067 | state->fe.demodulator_priv = state; |
1068 | i2c_set_clientdata(client, state); | ||
1086 | 1069 | ||
1087 | /* powerup */ | 1070 | /* powerup */ |
1088 | io_ret = si2165_writereg8(state, 0x0000, state->config.chip_mode); | 1071 | ret = si2165_writereg8(state, 0x0000, state->config.chip_mode); |
1089 | if (io_ret < 0) | 1072 | if (ret < 0) |
1090 | goto error; | 1073 | goto nodev_error; |
1091 | 1074 | ||
1092 | io_ret = si2165_readreg8(state, 0x0000, &val); | 1075 | ret = si2165_readreg8(state, 0x0000, &val); |
1093 | if (io_ret < 0) | 1076 | if (ret < 0) |
1094 | goto error; | 1077 | goto nodev_error; |
1095 | if (val != state->config.chip_mode) | 1078 | if (val != state->config.chip_mode) |
1096 | goto error; | 1079 | goto nodev_error; |
1097 | 1080 | ||
1098 | io_ret = si2165_readreg8(state, 0x0023, &state->chip_revcode); | 1081 | ret = si2165_readreg8(state, 0x0023, &state->chip_revcode); |
1099 | if (io_ret < 0) | 1082 | if (ret < 0) |
1100 | goto error; | 1083 | goto nodev_error; |
1101 | 1084 | ||
1102 | io_ret = si2165_readreg8(state, 0x0118, &state->chip_type); | 1085 | ret = si2165_readreg8(state, 0x0118, &state->chip_type); |
1103 | if (io_ret < 0) | 1086 | if (ret < 0) |
1104 | goto error; | 1087 | goto nodev_error; |
1105 | 1088 | ||
1106 | /* powerdown */ | 1089 | /* powerdown */ |
1107 | io_ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF); | 1090 | ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF); |
1108 | if (io_ret < 0) | 1091 | if (ret < 0) |
1109 | goto error; | 1092 | goto nodev_error; |
1110 | 1093 | ||
1111 | if (state->chip_revcode < 26) | 1094 | if (state->chip_revcode < 26) |
1112 | rev_char = 'A' + state->chip_revcode; | 1095 | rev_char = 'A' + state->chip_revcode; |
@@ -1124,12 +1107,12 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config, | |||
1124 | state->has_dvbc = true; | 1107 | state->has_dvbc = true; |
1125 | break; | 1108 | break; |
1126 | default: | 1109 | default: |
1127 | dev_err(&state->i2c->dev, "%s: Unsupported Silicon Labs chip (type %d, rev %d)\n", | 1110 | dev_err(&state->client->dev, "%s: Unsupported Silicon Labs chip (type %d, rev %d)\n", |
1128 | KBUILD_MODNAME, state->chip_type, state->chip_revcode); | 1111 | KBUILD_MODNAME, state->chip_type, state->chip_revcode); |
1129 | goto error; | 1112 | goto nodev_error; |
1130 | } | 1113 | } |
1131 | 1114 | ||
1132 | dev_info(&state->i2c->dev, | 1115 | dev_info(&state->client->dev, |
1133 | "%s: Detected Silicon Labs %s-%c (type %d, rev %d)\n", | 1116 | "%s: Detected Silicon Labs %s-%c (type %d, rev %d)\n", |
1134 | KBUILD_MODNAME, chip_name, rev_char, state->chip_type, | 1117 | KBUILD_MODNAME, chip_name, rev_char, state->chip_type, |
1135 | state->chip_revcode); | 1118 | state->chip_revcode); |
@@ -1149,13 +1132,46 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config, | |||
1149 | sizeof(state->fe.ops.info.name)); | 1132 | sizeof(state->fe.ops.info.name)); |
1150 | } | 1133 | } |
1151 | 1134 | ||
1152 | return &state->fe; | 1135 | /* return fe pointer */ |
1136 | *pdata->fe = &state->fe; | ||
1137 | |||
1138 | return 0; | ||
1153 | 1139 | ||
1140 | nodev_error: | ||
1141 | ret = -ENODEV; | ||
1154 | error: | 1142 | error: |
1155 | kfree(state); | 1143 | kfree(state); |
1156 | return NULL; | 1144 | dev_dbg(&client->dev, "failed=%d\n", ret); |
1145 | return ret; | ||
1157 | } | 1146 | } |
1158 | EXPORT_SYMBOL(si2165_attach); | 1147 | |
1148 | static int si2165_remove(struct i2c_client *client) | ||
1149 | { | ||
1150 | struct si2165_state *state = i2c_get_clientdata(client); | ||
1151 | |||
1152 | dev_dbg(&client->dev, "\n"); | ||
1153 | |||
1154 | kfree(state); | ||
1155 | return 0; | ||
1156 | } | ||
1157 | |||
1158 | static const struct i2c_device_id si2165_id_table[] = { | ||
1159 | {"si2165", 0}, | ||
1160 | {} | ||
1161 | }; | ||
1162 | MODULE_DEVICE_TABLE(i2c, si2165_id_table); | ||
1163 | |||
1164 | static struct i2c_driver si2165_driver = { | ||
1165 | .driver = { | ||
1166 | .owner = THIS_MODULE, | ||
1167 | .name = "si2165", | ||
1168 | }, | ||
1169 | .probe = si2165_probe, | ||
1170 | .remove = si2165_remove, | ||
1171 | .id_table = si2165_id_table, | ||
1172 | }; | ||
1173 | |||
1174 | module_i2c_driver(si2165_driver); | ||
1159 | 1175 | ||
1160 | module_param(debug, int, 0644); | 1176 | module_param(debug, int, 0644); |
1161 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | 1177 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); |
diff --git a/drivers/media/dvb-frontends/si2165.h b/drivers/media/dvb-frontends/si2165.h index 8a15d6a9c552..76c2ca7d7edb 100644 --- a/drivers/media/dvb-frontends/si2165.h +++ b/drivers/media/dvb-frontends/si2165.h | |||
@@ -28,10 +28,15 @@ enum { | |||
28 | SI2165_MODE_PLL_XTAL = 0x21 | 28 | SI2165_MODE_PLL_XTAL = 0x21 |
29 | }; | 29 | }; |
30 | 30 | ||
31 | struct si2165_config { | 31 | /* I2C addresses |
32 | /* i2c addr | 32 | * possible values: 0x64,0x65,0x66,0x67 |
33 | * possible values: 0x64,0x65,0x66,0x67 */ | 33 | */ |
34 | u8 i2c_addr; | 34 | struct si2165_platform_data { |
35 | /* | ||
36 | * frontend | ||
37 | * returned by driver | ||
38 | */ | ||
39 | struct dvb_frontend **fe; | ||
35 | 40 | ||
36 | /* external clock or XTAL */ | 41 | /* external clock or XTAL */ |
37 | u8 chip_mode; | 42 | u8 chip_mode; |
@@ -45,18 +50,4 @@ struct si2165_config { | |||
45 | bool inversion; | 50 | bool inversion; |
46 | }; | 51 | }; |
47 | 52 | ||
48 | #if IS_REACHABLE(CONFIG_DVB_SI2165) | ||
49 | struct dvb_frontend *si2165_attach( | ||
50 | const struct si2165_config *config, | ||
51 | struct i2c_adapter *i2c); | ||
52 | #else | ||
53 | static inline struct dvb_frontend *si2165_attach( | ||
54 | const struct si2165_config *config, | ||
55 | struct i2c_adapter *i2c) | ||
56 | { | ||
57 | pr_warn("%s: driver disabled by Kconfig\n", __func__); | ||
58 | return NULL; | ||
59 | } | ||
60 | #endif /* CONFIG_DVB_SI2165 */ | ||
61 | |||
62 | #endif /* _DVB_SI2165_H */ | 53 | #endif /* _DVB_SI2165_H */ |
diff --git a/drivers/media/dvb-frontends/si2165_priv.h b/drivers/media/dvb-frontends/si2165_priv.h index 2b70cf12cd79..e5932118834b 100644 --- a/drivers/media/dvb-frontends/si2165_priv.h +++ b/drivers/media/dvb-frontends/si2165_priv.h | |||
@@ -20,4 +20,21 @@ | |||
20 | 20 | ||
21 | #define SI2165_FIRMWARE_REV_D "dvb-demod-si2165.fw" | 21 | #define SI2165_FIRMWARE_REV_D "dvb-demod-si2165.fw" |
22 | 22 | ||
23 | struct si2165_config { | ||
24 | /* i2c addr | ||
25 | * possible values: 0x64,0x65,0x66,0x67 */ | ||
26 | u8 i2c_addr; | ||
27 | |||
28 | /* external clock or XTAL */ | ||
29 | u8 chip_mode; | ||
30 | |||
31 | /* frequency of external clock or xtal in Hz | ||
32 | * possible values: 4000000, 16000000, 20000000, 240000000, 27000000 | ||
33 | */ | ||
34 | u32 ref_freq_Hz; | ||
35 | |||
36 | /* invert the spectrum */ | ||
37 | bool inversion; | ||
38 | }; | ||
39 | |||
23 | #endif /* _DVB_SI2165_PRIV */ | 40 | #endif /* _DVB_SI2165_PRIV */ |
diff --git a/drivers/media/dvb-frontends/stb6000.c b/drivers/media/dvb-frontends/stb6000.c index a0c3c526b132..73347d51f340 100644 --- a/drivers/media/dvb-frontends/stb6000.c +++ b/drivers/media/dvb-frontends/stb6000.c | |||
@@ -186,7 +186,7 @@ static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency) | |||
186 | return 0; | 186 | return 0; |
187 | } | 187 | } |
188 | 188 | ||
189 | static struct dvb_tuner_ops stb6000_tuner_ops = { | 189 | static const struct dvb_tuner_ops stb6000_tuner_ops = { |
190 | .info = { | 190 | .info = { |
191 | .name = "ST STB6000", | 191 | .name = "ST STB6000", |
192 | .frequency_min = 950000, | 192 | .frequency_min = 950000, |
diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c index b9c2511bf019..5add1182c3ca 100644 --- a/drivers/media/dvb-frontends/stb6100.c +++ b/drivers/media/dvb-frontends/stb6100.c | |||
@@ -522,7 +522,7 @@ static int stb6100_set_params(struct dvb_frontend *fe) | |||
522 | return 0; | 522 | return 0; |
523 | } | 523 | } |
524 | 524 | ||
525 | static struct dvb_tuner_ops stb6100_ops = { | 525 | static const struct dvb_tuner_ops stb6100_ops = { |
526 | .info = { | 526 | .info = { |
527 | .name = "STB6100 Silicon Tuner", | 527 | .name = "STB6100 Silicon Tuner", |
528 | .frequency_min = 950000, | 528 | .frequency_min = 950000, |
diff --git a/drivers/media/dvb-frontends/stv6110.c b/drivers/media/dvb-frontends/stv6110.c index 91c6dcf65d2a..66a5a7f2295c 100644 --- a/drivers/media/dvb-frontends/stv6110.c +++ b/drivers/media/dvb-frontends/stv6110.c | |||
@@ -382,7 +382,7 @@ static int stv6110_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | |||
382 | return 0; | 382 | return 0; |
383 | } | 383 | } |
384 | 384 | ||
385 | static struct dvb_tuner_ops stv6110_tuner_ops = { | 385 | static const struct dvb_tuner_ops stv6110_tuner_ops = { |
386 | .info = { | 386 | .info = { |
387 | .name = "ST STV6110", | 387 | .name = "ST STV6110", |
388 | .frequency_min = 950000, | 388 | .frequency_min = 950000, |
diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c index a62c01e454f5..c611ad210b5c 100644 --- a/drivers/media/dvb-frontends/stv6110x.c +++ b/drivers/media/dvb-frontends/stv6110x.c | |||
@@ -345,7 +345,7 @@ static int stv6110x_release(struct dvb_frontend *fe) | |||
345 | return 0; | 345 | return 0; |
346 | } | 346 | } |
347 | 347 | ||
348 | static struct dvb_tuner_ops stv6110x_ops = { | 348 | static const struct dvb_tuner_ops stv6110x_ops = { |
349 | .info = { | 349 | .info = { |
350 | .name = "STV6110(A) Silicon Tuner", | 350 | .name = "STV6110(A) Silicon Tuner", |
351 | .frequency_min = 950000, | 351 | .frequency_min = 950000, |
diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c index de0a1c110972..bc247f9b553a 100644 --- a/drivers/media/dvb-frontends/tda18271c2dd.c +++ b/drivers/media/dvb-frontends/tda18271c2dd.c | |||
@@ -1217,7 +1217,7 @@ static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | |||
1217 | } | 1217 | } |
1218 | 1218 | ||
1219 | 1219 | ||
1220 | static struct dvb_tuner_ops tuner_ops = { | 1220 | static const struct dvb_tuner_ops tuner_ops = { |
1221 | .info = { | 1221 | .info = { |
1222 | .name = "NXP TDA18271C2D", | 1222 | .name = "NXP TDA18271C2D", |
1223 | .frequency_min = 47125000, | 1223 | .frequency_min = 47125000, |
diff --git a/drivers/media/dvb-frontends/tda665x.c b/drivers/media/dvb-frontends/tda665x.c index 82f8cc534f33..7ca965987f40 100644 --- a/drivers/media/dvb-frontends/tda665x.c +++ b/drivers/media/dvb-frontends/tda665x.c | |||
@@ -206,7 +206,7 @@ static int tda665x_release(struct dvb_frontend *fe) | |||
206 | return 0; | 206 | return 0; |
207 | } | 207 | } |
208 | 208 | ||
209 | static struct dvb_tuner_ops tda665x_ops = { | 209 | static const struct dvb_tuner_ops tda665x_ops = { |
210 | .get_status = tda665x_get_status, | 210 | .get_status = tda665x_get_status, |
211 | .set_params = tda665x_set_params, | 211 | .set_params = tda665x_set_params, |
212 | .get_frequency = tda665x_get_frequency, | 212 | .get_frequency = tda665x_get_frequency, |
diff --git a/drivers/media/dvb-frontends/tda8261.c b/drivers/media/dvb-frontends/tda8261.c index 3285b1bc4642..e0df93191b9e 100644 --- a/drivers/media/dvb-frontends/tda8261.c +++ b/drivers/media/dvb-frontends/tda8261.c | |||
@@ -161,7 +161,7 @@ static int tda8261_release(struct dvb_frontend *fe) | |||
161 | return 0; | 161 | return 0; |
162 | } | 162 | } |
163 | 163 | ||
164 | static struct dvb_tuner_ops tda8261_ops = { | 164 | static const struct dvb_tuner_ops tda8261_ops = { |
165 | 165 | ||
166 | .info = { | 166 | .info = { |
167 | .name = "TDA8261", | 167 | .name = "TDA8261", |
diff --git a/drivers/media/dvb-frontends/tda826x.c b/drivers/media/dvb-frontends/tda826x.c index 04bbcc24de0a..2ec671df1441 100644 --- a/drivers/media/dvb-frontends/tda826x.c +++ b/drivers/media/dvb-frontends/tda826x.c | |||
@@ -129,7 +129,7 @@ static int tda826x_get_frequency(struct dvb_frontend *fe, u32 *frequency) | |||
129 | return 0; | 129 | return 0; |
130 | } | 130 | } |
131 | 131 | ||
132 | static struct dvb_tuner_ops tda826x_tuner_ops = { | 132 | static const struct dvb_tuner_ops tda826x_tuner_ops = { |
133 | .info = { | 133 | .info = { |
134 | .name = "Philips TDA826X", | 134 | .name = "Philips TDA826X", |
135 | .frequency_min = 950000, | 135 | .frequency_min = 950000, |
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c index 14b410ffe612..a9f6bbea6df3 100644 --- a/drivers/media/dvb-frontends/ts2020.c +++ b/drivers/media/dvb-frontends/ts2020.c | |||
@@ -496,7 +496,7 @@ static int ts2020_read_signal_strength(struct dvb_frontend *fe, | |||
496 | return 0; | 496 | return 0; |
497 | } | 497 | } |
498 | 498 | ||
499 | static struct dvb_tuner_ops ts2020_tuner_ops = { | 499 | static const struct dvb_tuner_ops ts2020_tuner_ops = { |
500 | .info = { | 500 | .info = { |
501 | .name = "TS2020", | 501 | .name = "TS2020", |
502 | .frequency_min = 950000, | 502 | .frequency_min = 950000, |
diff --git a/drivers/media/dvb-frontends/tua6100.c b/drivers/media/dvb-frontends/tua6100.c index 029384d1fddd..6da12b9e55eb 100644 --- a/drivers/media/dvb-frontends/tua6100.c +++ b/drivers/media/dvb-frontends/tua6100.c | |||
@@ -157,7 +157,7 @@ static int tua6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) | |||
157 | return 0; | 157 | return 0; |
158 | } | 158 | } |
159 | 159 | ||
160 | static struct dvb_tuner_ops tua6100_tuner_ops = { | 160 | static const struct dvb_tuner_ops tua6100_tuner_ops = { |
161 | .info = { | 161 | .info = { |
162 | .name = "Infineon TUA6100", | 162 | .name = "Infineon TUA6100", |
163 | .frequency_min = 950000, | 163 | .frequency_min = 950000, |
diff --git a/drivers/media/dvb-frontends/zl10036.c b/drivers/media/dvb-frontends/zl10036.c index 0903d461b8fa..7ed81315965f 100644 --- a/drivers/media/dvb-frontends/zl10036.c +++ b/drivers/media/dvb-frontends/zl10036.c | |||
@@ -446,7 +446,7 @@ static int zl10036_init(struct dvb_frontend *fe) | |||
446 | return ret; | 446 | return ret; |
447 | } | 447 | } |
448 | 448 | ||
449 | static struct dvb_tuner_ops zl10036_tuner_ops = { | 449 | static const struct dvb_tuner_ops zl10036_tuner_ops = { |
450 | .info = { | 450 | .info = { |
451 | .name = "Zarlink ZL10036", | 451 | .name = "Zarlink ZL10036", |
452 | .frequency_min = 950000, | 452 | .frequency_min = 950000, |
diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c index ee09ec26c553..f8c271be196c 100644 --- a/drivers/media/dvb-frontends/zl10039.c +++ b/drivers/media/dvb-frontends/zl10039.c | |||
@@ -255,7 +255,7 @@ static int zl10039_release(struct dvb_frontend *fe) | |||
255 | return 0; | 255 | return 0; |
256 | } | 256 | } |
257 | 257 | ||
258 | static struct dvb_tuner_ops zl10039_ops = { | 258 | static const struct dvb_tuner_ops zl10039_ops = { |
259 | .release = zl10039_release, | 259 | .release = zl10039_release, |
260 | .init = zl10039_init, | 260 | .init = zl10039_init, |
261 | .sleep = zl10039_sleep, | 261 | .sleep = zl10039_sleep, |
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index ce9006e10a30..2669b4bad910 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig | |||
@@ -21,7 +21,7 @@ config VIDEO_IR_I2C | |||
21 | # Encoder / Decoder module configuration | 21 | # Encoder / Decoder module configuration |
22 | # | 22 | # |
23 | 23 | ||
24 | menu "Encoders, decoders, sensors and other helper chips" | 24 | menu "I2C Encoders, decoders, sensors and other helper chips" |
25 | visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST | 25 | visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST |
26 | 26 | ||
27 | comment "Audio decoders, processors and mixers" | 27 | comment "Audio decoders, processors and mixers" |
@@ -187,7 +187,7 @@ comment "Video decoders" | |||
187 | 187 | ||
188 | config VIDEO_ADV7180 | 188 | config VIDEO_ADV7180 |
189 | tristate "Analog Devices ADV7180 decoder" | 189 | tristate "Analog Devices ADV7180 decoder" |
190 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API | 190 | depends on GPIOLIB && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
191 | ---help--- | 191 | ---help--- |
192 | Support for the Analog Devices ADV7180 video decoder. | 192 | Support for the Analog Devices ADV7180 video decoder. |
193 | 193 | ||
@@ -295,6 +295,13 @@ config VIDEO_ML86V7667 | |||
295 | To compile this driver as a module, choose M here: the | 295 | To compile this driver as a module, choose M here: the |
296 | module will be called ml86v7667. | 296 | module will be called ml86v7667. |
297 | 297 | ||
298 | config VIDEO_AD5820 | ||
299 | tristate "AD5820 lens voice coil support" | ||
300 | depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER | ||
301 | ---help--- | ||
302 | This is a driver for the AD5820 camera lens voice coil. | ||
303 | It is used for example in Nokia N900 (RX-51). | ||
304 | |||
298 | config VIDEO_SAA7110 | 305 | config VIDEO_SAA7110 |
299 | tristate "Philips SAA7110 video decoder" | 306 | tristate "Philips SAA7110 video decoder" |
300 | depends on VIDEO_V4L2 && I2C | 307 | depends on VIDEO_V4L2 && I2C |
@@ -571,6 +578,13 @@ config VIDEO_MT9M032 | |||
571 | This driver supports MT9M032 camera sensors from Aptina, monochrome | 578 | This driver supports MT9M032 camera sensors from Aptina, monochrome |
572 | models only. | 579 | models only. |
573 | 580 | ||
581 | config VIDEO_MT9M111 | ||
582 | tristate "mt9m111, mt9m112 and mt9m131 support" | ||
583 | depends on I2C && VIDEO_V4L2 | ||
584 | help | ||
585 | This driver supports MT9M111, MT9M112 and MT9M131 cameras from | ||
586 | Micron/Aptina | ||
587 | |||
574 | config VIDEO_MT9P031 | 588 | config VIDEO_MT9P031 |
575 | tristate "Aptina MT9P031 support" | 589 | tristate "Aptina MT9P031 support" |
576 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | 590 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API |
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 94f2c99e890d..92773b2e6225 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_SAA6752HS) += saa6752hs.o | 21 | obj-$(CONFIG_VIDEO_SAA6752HS) += saa6752hs.o |
22 | obj-$(CONFIG_VIDEO_AD5820) += ad5820.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 |
@@ -59,6 +60,7 @@ obj-$(CONFIG_VIDEO_OV7640) += ov7640.o | |||
59 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o | 60 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o |
60 | obj-$(CONFIG_VIDEO_OV9650) += ov9650.o | 61 | obj-$(CONFIG_VIDEO_OV9650) += ov9650.o |
61 | obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o | 62 | obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o |
63 | obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o | ||
62 | obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o | 64 | obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o |
63 | obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o | 65 | obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o |
64 | obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o | 66 | obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o |
diff --git a/drivers/media/i2c/ad5820.c b/drivers/media/i2c/ad5820.c new file mode 100644 index 000000000000..beab2f381b81 --- /dev/null +++ b/drivers/media/i2c/ad5820.c | |||
@@ -0,0 +1,372 @@ | |||
1 | /* | ||
2 | * drivers/media/i2c/ad5820.c | ||
3 | * | ||
4 | * AD5820 DAC driver for camera voice coil focus. | ||
5 | * | ||
6 | * Copyright (C) 2008 Nokia Corporation | ||
7 | * Copyright (C) 2007 Texas Instruments | ||
8 | * Copyright (C) 2016 Pavel Machek <pavel@ucw.cz> | ||
9 | * | ||
10 | * Contact: Tuukka Toivonen <tuukkat76@gmail.com> | ||
11 | * Sakari Ailus <sakari.ailus@iki.fi> | ||
12 | * | ||
13 | * Based on af_d88.c by Texas Instruments. | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * version 2 as published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | * General Public License for more details. | ||
23 | */ | ||
24 | |||
25 | #include <linux/errno.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/regulator/consumer.h> | ||
30 | |||
31 | #include <media/v4l2-ctrls.h> | ||
32 | #include <media/v4l2-device.h> | ||
33 | #include <media/v4l2-subdev.h> | ||
34 | |||
35 | #define AD5820_NAME "ad5820" | ||
36 | |||
37 | /* Register definitions */ | ||
38 | #define AD5820_POWER_DOWN (1 << 15) | ||
39 | #define AD5820_DAC_SHIFT 4 | ||
40 | #define AD5820_RAMP_MODE_LINEAR (0 << 3) | ||
41 | #define AD5820_RAMP_MODE_64_16 (1 << 3) | ||
42 | |||
43 | #define CODE_TO_RAMP_US(s) ((s) == 0 ? 0 : (1 << ((s) - 1)) * 50) | ||
44 | #define RAMP_US_TO_CODE(c) fls(((c) + ((c)>>1)) / 50) | ||
45 | |||
46 | #define to_ad5820_device(sd) container_of(sd, struct ad5820_device, subdev) | ||
47 | |||
48 | struct ad5820_device { | ||
49 | struct v4l2_subdev subdev; | ||
50 | struct ad5820_platform_data *platform_data; | ||
51 | struct regulator *vana; | ||
52 | |||
53 | struct v4l2_ctrl_handler ctrls; | ||
54 | u32 focus_absolute; | ||
55 | u32 focus_ramp_time; | ||
56 | u32 focus_ramp_mode; | ||
57 | |||
58 | struct mutex power_lock; | ||
59 | int power_count; | ||
60 | |||
61 | bool standby; | ||
62 | }; | ||
63 | |||
64 | static int ad5820_write(struct ad5820_device *coil, u16 data) | ||
65 | { | ||
66 | struct i2c_client *client = v4l2_get_subdevdata(&coil->subdev); | ||
67 | struct i2c_msg msg; | ||
68 | int r; | ||
69 | |||
70 | if (!client->adapter) | ||
71 | return -ENODEV; | ||
72 | |||
73 | data = cpu_to_be16(data); | ||
74 | msg.addr = client->addr; | ||
75 | msg.flags = 0; | ||
76 | msg.len = 2; | ||
77 | msg.buf = (u8 *)&data; | ||
78 | |||
79 | r = i2c_transfer(client->adapter, &msg, 1); | ||
80 | if (r < 0) { | ||
81 | dev_err(&client->dev, "write failed, error %d\n", r); | ||
82 | return r; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * Calculate status word and write it to the device based on current | ||
90 | * values of V4L2 controls. It is assumed that the stored V4L2 control | ||
91 | * values are properly limited and rounded. | ||
92 | */ | ||
93 | static int ad5820_update_hw(struct ad5820_device *coil) | ||
94 | { | ||
95 | u16 status; | ||
96 | |||
97 | status = RAMP_US_TO_CODE(coil->focus_ramp_time); | ||
98 | status |= coil->focus_ramp_mode | ||
99 | ? AD5820_RAMP_MODE_64_16 : AD5820_RAMP_MODE_LINEAR; | ||
100 | status |= coil->focus_absolute << AD5820_DAC_SHIFT; | ||
101 | |||
102 | if (coil->standby) | ||
103 | status |= AD5820_POWER_DOWN; | ||
104 | |||
105 | return ad5820_write(coil, status); | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * Power handling | ||
110 | */ | ||
111 | static int ad5820_power_off(struct ad5820_device *coil, bool standby) | ||
112 | { | ||
113 | int ret = 0, ret2; | ||
114 | |||
115 | /* | ||
116 | * Go to standby first as real power off my be denied by the hardware | ||
117 | * (single power line control for both coil and sensor). | ||
118 | */ | ||
119 | if (standby) { | ||
120 | coil->standby = true; | ||
121 | ret = ad5820_update_hw(coil); | ||
122 | } | ||
123 | |||
124 | ret2 = regulator_disable(coil->vana); | ||
125 | if (ret) | ||
126 | return ret; | ||
127 | return ret2; | ||
128 | } | ||
129 | |||
130 | static int ad5820_power_on(struct ad5820_device *coil, bool restore) | ||
131 | { | ||
132 | int ret; | ||
133 | |||
134 | ret = regulator_enable(coil->vana); | ||
135 | if (ret < 0) | ||
136 | return ret; | ||
137 | |||
138 | if (restore) { | ||
139 | /* Restore the hardware settings. */ | ||
140 | coil->standby = false; | ||
141 | ret = ad5820_update_hw(coil); | ||
142 | if (ret) | ||
143 | goto fail; | ||
144 | } | ||
145 | return 0; | ||
146 | |||
147 | fail: | ||
148 | coil->standby = true; | ||
149 | regulator_disable(coil->vana); | ||
150 | |||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * V4L2 controls | ||
156 | */ | ||
157 | static int ad5820_set_ctrl(struct v4l2_ctrl *ctrl) | ||
158 | { | ||
159 | struct ad5820_device *coil = | ||
160 | container_of(ctrl->handler, struct ad5820_device, ctrls); | ||
161 | |||
162 | switch (ctrl->id) { | ||
163 | case V4L2_CID_FOCUS_ABSOLUTE: | ||
164 | coil->focus_absolute = ctrl->val; | ||
165 | return ad5820_update_hw(coil); | ||
166 | } | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static const struct v4l2_ctrl_ops ad5820_ctrl_ops = { | ||
172 | .s_ctrl = ad5820_set_ctrl, | ||
173 | }; | ||
174 | |||
175 | |||
176 | static int ad5820_init_controls(struct ad5820_device *coil) | ||
177 | { | ||
178 | v4l2_ctrl_handler_init(&coil->ctrls, 1); | ||
179 | |||
180 | /* | ||
181 | * V4L2_CID_FOCUS_ABSOLUTE | ||
182 | * | ||
183 | * Minimum current is 0 mA, maximum is 100 mA. Thus, 1 code is | ||
184 | * equivalent to 100/1023 = 0.0978 mA. Nevertheless, we do not use [mA] | ||
185 | * for focus position, because it is meaningless for user. Meaningful | ||
186 | * would be to use focus distance or even its inverse, but since the | ||
187 | * driver doesn't have sufficiently knowledge to do the conversion, we | ||
188 | * will just use abstract codes here. In any case, smaller value = focus | ||
189 | * position farther from camera. The default zero value means focus at | ||
190 | * infinity, and also least current consumption. | ||
191 | */ | ||
192 | v4l2_ctrl_new_std(&coil->ctrls, &ad5820_ctrl_ops, | ||
193 | V4L2_CID_FOCUS_ABSOLUTE, 0, 1023, 1, 0); | ||
194 | |||
195 | if (coil->ctrls.error) | ||
196 | return coil->ctrls.error; | ||
197 | |||
198 | coil->focus_absolute = 0; | ||
199 | coil->focus_ramp_time = 0; | ||
200 | coil->focus_ramp_mode = 0; | ||
201 | |||
202 | coil->subdev.ctrl_handler = &coil->ctrls; | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | /* | ||
208 | * V4L2 subdev operations | ||
209 | */ | ||
210 | static int ad5820_registered(struct v4l2_subdev *subdev) | ||
211 | { | ||
212 | struct ad5820_device *coil = to_ad5820_device(subdev); | ||
213 | |||
214 | return ad5820_init_controls(coil); | ||
215 | } | ||
216 | |||
217 | static int | ||
218 | ad5820_set_power(struct v4l2_subdev *subdev, int on) | ||
219 | { | ||
220 | struct ad5820_device *coil = to_ad5820_device(subdev); | ||
221 | int ret = 0; | ||
222 | |||
223 | mutex_lock(&coil->power_lock); | ||
224 | |||
225 | /* | ||
226 | * If the power count is modified from 0 to != 0 or from != 0 to 0, | ||
227 | * update the power state. | ||
228 | */ | ||
229 | if (coil->power_count == !on) { | ||
230 | ret = on ? ad5820_power_on(coil, true) : | ||
231 | ad5820_power_off(coil, true); | ||
232 | if (ret < 0) | ||
233 | goto done; | ||
234 | } | ||
235 | |||
236 | /* Update the power count. */ | ||
237 | coil->power_count += on ? 1 : -1; | ||
238 | WARN_ON(coil->power_count < 0); | ||
239 | |||
240 | done: | ||
241 | mutex_unlock(&coil->power_lock); | ||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | static int ad5820_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
246 | { | ||
247 | return ad5820_set_power(sd, 1); | ||
248 | } | ||
249 | |||
250 | static int ad5820_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
251 | { | ||
252 | return ad5820_set_power(sd, 0); | ||
253 | } | ||
254 | |||
255 | static const struct v4l2_subdev_core_ops ad5820_core_ops = { | ||
256 | .s_power = ad5820_set_power, | ||
257 | }; | ||
258 | |||
259 | static const struct v4l2_subdev_ops ad5820_ops = { | ||
260 | .core = &ad5820_core_ops, | ||
261 | }; | ||
262 | |||
263 | static const struct v4l2_subdev_internal_ops ad5820_internal_ops = { | ||
264 | .registered = ad5820_registered, | ||
265 | .open = ad5820_open, | ||
266 | .close = ad5820_close, | ||
267 | }; | ||
268 | |||
269 | /* | ||
270 | * I2C driver | ||
271 | */ | ||
272 | static int __maybe_unused ad5820_suspend(struct device *dev) | ||
273 | { | ||
274 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
275 | struct v4l2_subdev *subdev = i2c_get_clientdata(client); | ||
276 | struct ad5820_device *coil = to_ad5820_device(subdev); | ||
277 | |||
278 | if (!coil->power_count) | ||
279 | return 0; | ||
280 | |||
281 | return ad5820_power_off(coil, false); | ||
282 | } | ||
283 | |||
284 | static int __maybe_unused ad5820_resume(struct device *dev) | ||
285 | { | ||
286 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
287 | struct v4l2_subdev *subdev = i2c_get_clientdata(client); | ||
288 | struct ad5820_device *coil = to_ad5820_device(subdev); | ||
289 | |||
290 | if (!coil->power_count) | ||
291 | return 0; | ||
292 | |||
293 | return ad5820_power_on(coil, true); | ||
294 | } | ||
295 | |||
296 | static int ad5820_probe(struct i2c_client *client, | ||
297 | const struct i2c_device_id *devid) | ||
298 | { | ||
299 | struct ad5820_device *coil; | ||
300 | int ret; | ||
301 | |||
302 | coil = devm_kzalloc(&client->dev, sizeof(*coil), GFP_KERNEL); | ||
303 | if (!coil) | ||
304 | return -ENOMEM; | ||
305 | |||
306 | coil->vana = devm_regulator_get(&client->dev, "VANA"); | ||
307 | if (IS_ERR(coil->vana)) { | ||
308 | ret = PTR_ERR(coil->vana); | ||
309 | if (ret != -EPROBE_DEFER) | ||
310 | dev_err(&client->dev, "could not get regulator for vana\n"); | ||
311 | return ret; | ||
312 | } | ||
313 | |||
314 | mutex_init(&coil->power_lock); | ||
315 | |||
316 | v4l2_i2c_subdev_init(&coil->subdev, client, &ad5820_ops); | ||
317 | coil->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
318 | coil->subdev.internal_ops = &ad5820_internal_ops; | ||
319 | strcpy(coil->subdev.name, "ad5820 focus"); | ||
320 | |||
321 | ret = media_entity_pads_init(&coil->subdev.entity, 0, NULL); | ||
322 | if (ret < 0) | ||
323 | goto cleanup2; | ||
324 | |||
325 | ret = v4l2_async_register_subdev(&coil->subdev); | ||
326 | if (ret < 0) | ||
327 | goto cleanup; | ||
328 | |||
329 | return ret; | ||
330 | |||
331 | cleanup2: | ||
332 | mutex_destroy(&coil->power_lock); | ||
333 | cleanup: | ||
334 | media_entity_cleanup(&coil->subdev.entity); | ||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | static int __exit ad5820_remove(struct i2c_client *client) | ||
339 | { | ||
340 | struct v4l2_subdev *subdev = i2c_get_clientdata(client); | ||
341 | struct ad5820_device *coil = to_ad5820_device(subdev); | ||
342 | |||
343 | v4l2_device_unregister_subdev(&coil->subdev); | ||
344 | v4l2_ctrl_handler_free(&coil->ctrls); | ||
345 | media_entity_cleanup(&coil->subdev.entity); | ||
346 | mutex_destroy(&coil->power_lock); | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static const struct i2c_device_id ad5820_id_table[] = { | ||
351 | { AD5820_NAME, 0 }, | ||
352 | { } | ||
353 | }; | ||
354 | MODULE_DEVICE_TABLE(i2c, ad5820_id_table); | ||
355 | |||
356 | static SIMPLE_DEV_PM_OPS(ad5820_pm, ad5820_suspend, ad5820_resume); | ||
357 | |||
358 | static struct i2c_driver ad5820_i2c_driver = { | ||
359 | .driver = { | ||
360 | .name = AD5820_NAME, | ||
361 | .pm = &ad5820_pm, | ||
362 | }, | ||
363 | .probe = ad5820_probe, | ||
364 | .remove = __exit_p(ad5820_remove), | ||
365 | .id_table = ad5820_id_table, | ||
366 | }; | ||
367 | |||
368 | module_i2c_driver(ad5820_i2c_driver); | ||
369 | |||
370 | MODULE_AUTHOR("Tuukka Toivonen"); | ||
371 | MODULE_DESCRIPTION("AD5820 camera lens driver"); | ||
372 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index 0462f461e679..50f354144ee7 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c | |||
@@ -98,7 +98,6 @@ struct ad9389b_state { | |||
98 | struct ad9389b_state_edid edid; | 98 | struct ad9389b_state_edid edid; |
99 | /* Running counter of the number of detected EDIDs (for debugging) */ | 99 | /* Running counter of the number of detected EDIDs (for debugging) */ |
100 | unsigned edid_detect_counter; | 100 | unsigned edid_detect_counter; |
101 | struct workqueue_struct *work_queue; | ||
102 | struct delayed_work edid_handler; /* work entry */ | 101 | struct delayed_work edid_handler; /* work entry */ |
103 | }; | 102 | }; |
104 | 103 | ||
@@ -843,8 +842,7 @@ static void ad9389b_edid_handler(struct work_struct *work) | |||
843 | v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__); | 842 | v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__); |
844 | ad9389b_s_power(sd, false); | 843 | ad9389b_s_power(sd, false); |
845 | ad9389b_s_power(sd, true); | 844 | ad9389b_s_power(sd, true); |
846 | queue_delayed_work(state->work_queue, | 845 | schedule_delayed_work(&state->edid_handler, EDID_DELAY); |
847 | &state->edid_handler, EDID_DELAY); | ||
848 | return; | 846 | return; |
849 | } | 847 | } |
850 | } | 848 | } |
@@ -933,8 +931,7 @@ static void ad9389b_update_monitor_present_status(struct v4l2_subdev *sd) | |||
933 | ad9389b_setup(sd); | 931 | ad9389b_setup(sd); |
934 | ad9389b_notify_monitor_detect(sd); | 932 | ad9389b_notify_monitor_detect(sd); |
935 | state->edid.read_retries = EDID_MAX_RETRIES; | 933 | state->edid.read_retries = EDID_MAX_RETRIES; |
936 | queue_delayed_work(state->work_queue, | 934 | schedule_delayed_work(&state->edid_handler, EDID_DELAY); |
937 | &state->edid_handler, EDID_DELAY); | ||
938 | } else if (!(status & MASK_AD9389B_HPD_DETECT)) { | 935 | } else if (!(status & MASK_AD9389B_HPD_DETECT)) { |
939 | v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__); | 936 | v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__); |
940 | state->have_monitor = false; | 937 | state->have_monitor = false; |
@@ -1065,8 +1062,7 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd) | |||
1065 | ad9389b_wr(sd, 0xc9, 0xf); | 1062 | ad9389b_wr(sd, 0xc9, 0xf); |
1066 | ad9389b_wr(sd, 0xc4, state->edid.segments); | 1063 | ad9389b_wr(sd, 0xc4, state->edid.segments); |
1067 | state->edid.read_retries = EDID_MAX_RETRIES; | 1064 | state->edid.read_retries = EDID_MAX_RETRIES; |
1068 | queue_delayed_work(state->work_queue, | 1065 | schedule_delayed_work(&state->edid_handler, EDID_DELAY); |
1069 | &state->edid_handler, EDID_DELAY); | ||
1070 | return false; | 1066 | return false; |
1071 | } | 1067 | } |
1072 | 1068 | ||
@@ -1170,13 +1166,6 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id * | |||
1170 | goto err_entity; | 1166 | goto err_entity; |
1171 | } | 1167 | } |
1172 | 1168 | ||
1173 | state->work_queue = create_singlethread_workqueue(sd->name); | ||
1174 | if (state->work_queue == NULL) { | ||
1175 | v4l2_err(sd, "could not create workqueue\n"); | ||
1176 | err = -ENOMEM; | ||
1177 | goto err_unreg; | ||
1178 | } | ||
1179 | |||
1180 | INIT_DELAYED_WORK(&state->edid_handler, ad9389b_edid_handler); | 1169 | INIT_DELAYED_WORK(&state->edid_handler, ad9389b_edid_handler); |
1181 | state->dv_timings = dv1080p60; | 1170 | state->dv_timings = dv1080p60; |
1182 | 1171 | ||
@@ -1187,8 +1176,6 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id * | |||
1187 | client->addr << 1, client->adapter->name); | 1176 | client->addr << 1, client->adapter->name); |
1188 | return 0; | 1177 | return 0; |
1189 | 1178 | ||
1190 | err_unreg: | ||
1191 | i2c_unregister_device(state->edid_i2c_client); | ||
1192 | err_entity: | 1179 | err_entity: |
1193 | media_entity_cleanup(&sd->entity); | 1180 | media_entity_cleanup(&sd->entity); |
1194 | err_hdl: | 1181 | err_hdl: |
@@ -1211,9 +1198,8 @@ static int ad9389b_remove(struct i2c_client *client) | |||
1211 | ad9389b_s_stream(sd, false); | 1198 | ad9389b_s_stream(sd, false); |
1212 | ad9389b_s_audio_stream(sd, false); | 1199 | ad9389b_s_audio_stream(sd, false); |
1213 | ad9389b_init_setup(sd); | 1200 | ad9389b_init_setup(sd); |
1214 | cancel_delayed_work(&state->edid_handler); | 1201 | cancel_delayed_work_sync(&state->edid_handler); |
1215 | i2c_unregister_device(state->edid_i2c_client); | 1202 | i2c_unregister_device(state->edid_i2c_client); |
1216 | destroy_workqueue(state->work_queue); | ||
1217 | v4l2_device_unregister_subdev(sd); | 1203 | v4l2_device_unregister_subdev(sd); |
1218 | media_entity_cleanup(&sd->entity); | 1204 | media_entity_cleanup(&sd->entity); |
1219 | v4l2_ctrl_handler_free(sd->ctrl_handler); | 1205 | v4l2_ctrl_handler_free(sd->ctrl_handler); |
@@ -1231,7 +1217,6 @@ MODULE_DEVICE_TABLE(i2c, ad9389b_id); | |||
1231 | 1217 | ||
1232 | static struct i2c_driver ad9389b_driver = { | 1218 | static struct i2c_driver ad9389b_driver = { |
1233 | .driver = { | 1219 | .driver = { |
1234 | .owner = THIS_MODULE, | ||
1235 | .name = "ad9389b", | 1220 | .name = "ad9389b", |
1236 | }, | 1221 | }, |
1237 | .probe = ad9389b_probe, | 1222 | .probe = ad9389b_probe, |
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 95cbc857f36e..cbed2bc29325 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/of.h> | 28 | #include <linux/of.h> |
29 | #include <linux/gpio/consumer.h> | ||
29 | #include <linux/videodev2.h> | 30 | #include <linux/videodev2.h> |
30 | #include <media/v4l2-ioctl.h> | 31 | #include <media/v4l2-ioctl.h> |
31 | #include <media/v4l2-event.h> | 32 | #include <media/v4l2-event.h> |
@@ -56,10 +57,11 @@ | |||
56 | 57 | ||
57 | #define ADV7182_REG_INPUT_VIDSEL 0x0002 | 58 | #define ADV7182_REG_INPUT_VIDSEL 0x0002 |
58 | 59 | ||
60 | #define ADV7180_REG_OUTPUT_CONTROL 0x0003 | ||
59 | #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004 | 61 | #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004 |
60 | #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5 | 62 | #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5 |
61 | 63 | ||
62 | #define ADV7180_REG_AUTODETECT_ENABLE 0x07 | 64 | #define ADV7180_REG_AUTODETECT_ENABLE 0x0007 |
63 | #define ADV7180_AUTODETECT_DEFAULT 0x7f | 65 | #define ADV7180_AUTODETECT_DEFAULT 0x7f |
64 | /* Contrast */ | 66 | /* Contrast */ |
65 | #define ADV7180_REG_CON 0x0008 /*Unsigned */ | 67 | #define ADV7180_REG_CON 0x0008 /*Unsigned */ |
@@ -100,6 +102,20 @@ | |||
100 | #define ADV7180_REG_IDENT 0x0011 | 102 | #define ADV7180_REG_IDENT 0x0011 |
101 | #define ADV7180_ID_7180 0x18 | 103 | #define ADV7180_ID_7180 0x18 |
102 | 104 | ||
105 | #define ADV7180_REG_STATUS3 0x0013 | ||
106 | #define ADV7180_REG_ANALOG_CLAMP_CTL 0x0014 | ||
107 | #define ADV7180_REG_SHAP_FILTER_CTL_1 0x0017 | ||
108 | #define ADV7180_REG_CTRL_2 0x001d | ||
109 | #define ADV7180_REG_VSYNC_FIELD_CTL_1 0x0031 | ||
110 | #define ADV7180_REG_MANUAL_WIN_CTL_1 0x003d | ||
111 | #define ADV7180_REG_MANUAL_WIN_CTL_2 0x003e | ||
112 | #define ADV7180_REG_MANUAL_WIN_CTL_3 0x003f | ||
113 | #define ADV7180_REG_LOCK_CNT 0x0051 | ||
114 | #define ADV7180_REG_CVBS_TRIM 0x0052 | ||
115 | #define ADV7180_REG_CLAMP_ADJ 0x005a | ||
116 | #define ADV7180_REG_RES_CIR 0x005f | ||
117 | #define ADV7180_REG_DIFF_MODE 0x0060 | ||
118 | |||
103 | #define ADV7180_REG_ICONF1 0x2040 | 119 | #define ADV7180_REG_ICONF1 0x2040 |
104 | #define ADV7180_ICONF1_ACTIVE_LOW 0x01 | 120 | #define ADV7180_ICONF1_ACTIVE_LOW 0x01 |
105 | #define ADV7180_ICONF1_PSYNC_ONLY 0x10 | 121 | #define ADV7180_ICONF1_PSYNC_ONLY 0x10 |
@@ -129,9 +145,15 @@ | |||
129 | #define ADV7180_REG_VPP_SLAVE_ADDR 0xFD | 145 | #define ADV7180_REG_VPP_SLAVE_ADDR 0xFD |
130 | #define ADV7180_REG_CSI_SLAVE_ADDR 0xFE | 146 | #define ADV7180_REG_CSI_SLAVE_ADDR 0xFE |
131 | 147 | ||
132 | #define ADV7180_REG_FLCONTROL 0x40e0 | 148 | #define ADV7180_REG_ACE_CTRL1 0x4080 |
149 | #define ADV7180_REG_ACE_CTRL5 0x4084 | ||
150 | #define ADV7180_REG_FLCONTROL 0x40e0 | ||
133 | #define ADV7180_FLCONTROL_FL_ENABLE 0x1 | 151 | #define ADV7180_FLCONTROL_FL_ENABLE 0x1 |
134 | 152 | ||
153 | #define ADV7180_REG_RST_CLAMP 0x809c | ||
154 | #define ADV7180_REG_AGC_ADJ1 0x80b6 | ||
155 | #define ADV7180_REG_AGC_ADJ2 0x80c0 | ||
156 | |||
135 | #define ADV7180_CSI_REG_PWRDN 0x00 | 157 | #define ADV7180_CSI_REG_PWRDN 0x00 |
136 | #define ADV7180_CSI_PWRDN 0x80 | 158 | #define ADV7180_CSI_PWRDN 0x80 |
137 | 159 | ||
@@ -192,6 +214,7 @@ struct adv7180_state { | |||
192 | struct media_pad pad; | 214 | struct media_pad pad; |
193 | struct mutex mutex; /* mutual excl. when accessing chip */ | 215 | struct mutex mutex; /* mutual excl. when accessing chip */ |
194 | int irq; | 216 | int irq; |
217 | struct gpio_desc *pwdn_gpio; | ||
195 | v4l2_std_id curr_norm; | 218 | v4l2_std_id curr_norm; |
196 | bool powered; | 219 | bool powered; |
197 | bool streaming; | 220 | bool streaming; |
@@ -442,6 +465,19 @@ static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) | |||
442 | return 0; | 465 | return 0; |
443 | } | 466 | } |
444 | 467 | ||
468 | static void adv7180_set_power_pin(struct adv7180_state *state, bool on) | ||
469 | { | ||
470 | if (!state->pwdn_gpio) | ||
471 | return; | ||
472 | |||
473 | if (on) { | ||
474 | gpiod_set_value_cansleep(state->pwdn_gpio, 0); | ||
475 | usleep_range(5000, 10000); | ||
476 | } else { | ||
477 | gpiod_set_value_cansleep(state->pwdn_gpio, 1); | ||
478 | } | ||
479 | } | ||
480 | |||
445 | static int adv7180_set_power(struct adv7180_state *state, bool on) | 481 | static int adv7180_set_power(struct adv7180_state *state, bool on) |
446 | { | 482 | { |
447 | u8 val; | 483 | u8 val; |
@@ -597,7 +633,7 @@ static int adv7180_enum_mbus_code(struct v4l2_subdev *sd, | |||
597 | if (code->index != 0) | 633 | if (code->index != 0) |
598 | return -EINVAL; | 634 | return -EINVAL; |
599 | 635 | ||
600 | code->code = MEDIA_BUS_FMT_YUYV8_2X8; | 636 | code->code = MEDIA_BUS_FMT_UYVY8_2X8; |
601 | 637 | ||
602 | return 0; | 638 | return 0; |
603 | } | 639 | } |
@@ -607,7 +643,7 @@ static int adv7180_mbus_fmt(struct v4l2_subdev *sd, | |||
607 | { | 643 | { |
608 | struct adv7180_state *state = to_state(sd); | 644 | struct adv7180_state *state = to_state(sd); |
609 | 645 | ||
610 | fmt->code = MEDIA_BUS_FMT_YUYV8_2X8; | 646 | fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; |
611 | fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; | 647 | fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; |
612 | fmt->width = 720; | 648 | fmt->width = 720; |
613 | fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576; | 649 | fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576; |
@@ -675,6 +711,7 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd, | |||
675 | { | 711 | { |
676 | struct adv7180_state *state = to_state(sd); | 712 | struct adv7180_state *state = to_state(sd); |
677 | struct v4l2_mbus_framefmt *framefmt; | 713 | struct v4l2_mbus_framefmt *framefmt; |
714 | int ret; | ||
678 | 715 | ||
679 | switch (format->format.field) { | 716 | switch (format->format.field) { |
680 | case V4L2_FIELD_NONE: | 717 | case V4L2_FIELD_NONE: |
@@ -686,8 +723,9 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd, | |||
686 | break; | 723 | break; |
687 | } | 724 | } |
688 | 725 | ||
726 | ret = adv7180_mbus_fmt(sd, &format->format); | ||
727 | |||
689 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | 728 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { |
690 | framefmt = &format->format; | ||
691 | if (state->field != format->format.field) { | 729 | if (state->field != format->format.field) { |
692 | state->field = format->format.field; | 730 | state->field = format->format.field; |
693 | adv7180_set_power(state, false); | 731 | adv7180_set_power(state, false); |
@@ -699,7 +737,7 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd, | |||
699 | *framefmt = format->format; | 737 | *framefmt = format->format; |
700 | } | 738 | } |
701 | 739 | ||
702 | return adv7180_mbus_fmt(sd, framefmt); | 740 | return ret; |
703 | } | 741 | } |
704 | 742 | ||
705 | static int adv7180_g_mbus_config(struct v4l2_subdev *sd, | 743 | static int adv7180_g_mbus_config(struct v4l2_subdev *sd, |
@@ -725,16 +763,16 @@ static int adv7180_g_mbus_config(struct v4l2_subdev *sd, | |||
725 | return 0; | 763 | return 0; |
726 | } | 764 | } |
727 | 765 | ||
728 | static int adv7180_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *cropcap) | 766 | static int adv7180_g_pixelaspect(struct v4l2_subdev *sd, struct v4l2_fract *aspect) |
729 | { | 767 | { |
730 | struct adv7180_state *state = to_state(sd); | 768 | struct adv7180_state *state = to_state(sd); |
731 | 769 | ||
732 | if (state->curr_norm & V4L2_STD_525_60) { | 770 | if (state->curr_norm & V4L2_STD_525_60) { |
733 | cropcap->pixelaspect.numerator = 11; | 771 | aspect->numerator = 11; |
734 | cropcap->pixelaspect.denominator = 10; | 772 | aspect->denominator = 10; |
735 | } else { | 773 | } else { |
736 | cropcap->pixelaspect.numerator = 54; | 774 | aspect->numerator = 54; |
737 | cropcap->pixelaspect.denominator = 59; | 775 | aspect->denominator = 59; |
738 | } | 776 | } |
739 | 777 | ||
740 | return 0; | 778 | return 0; |
@@ -787,7 +825,7 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = { | |||
787 | .g_input_status = adv7180_g_input_status, | 825 | .g_input_status = adv7180_g_input_status, |
788 | .s_routing = adv7180_s_routing, | 826 | .s_routing = adv7180_s_routing, |
789 | .g_mbus_config = adv7180_g_mbus_config, | 827 | .g_mbus_config = adv7180_g_mbus_config, |
790 | .cropcap = adv7180_cropcap, | 828 | .g_pixelaspect = adv7180_g_pixelaspect, |
791 | .g_tvnorms = adv7180_g_tvnorms, | 829 | .g_tvnorms = adv7180_g_tvnorms, |
792 | .s_stream = adv7180_s_stream, | 830 | .s_stream = adv7180_s_stream, |
793 | }; | 831 | }; |
@@ -886,16 +924,20 @@ static int adv7182_init(struct adv7180_state *state) | |||
886 | 924 | ||
887 | /* ADI required writes */ | 925 | /* ADI required writes */ |
888 | if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { | 926 | if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { |
889 | adv7180_write(state, 0x0003, 0x4e); | 927 | adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x4e); |
890 | adv7180_write(state, 0x0004, 0x57); | 928 | adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x57); |
891 | adv7180_write(state, 0x001d, 0xc0); | 929 | adv7180_write(state, ADV7180_REG_CTRL_2, 0xc0); |
892 | } else { | 930 | } else { |
893 | if (state->chip_info->flags & ADV7180_FLAG_V2) | 931 | if (state->chip_info->flags & ADV7180_FLAG_V2) |
894 | adv7180_write(state, 0x0004, 0x17); | 932 | adv7180_write(state, |
933 | ADV7180_REG_EXTENDED_OUTPUT_CONTROL, | ||
934 | 0x17); | ||
895 | else | 935 | else |
896 | adv7180_write(state, 0x0004, 0x07); | 936 | adv7180_write(state, |
897 | adv7180_write(state, 0x0003, 0x0c); | 937 | ADV7180_REG_EXTENDED_OUTPUT_CONTROL, |
898 | adv7180_write(state, 0x001d, 0x40); | 938 | 0x07); |
939 | adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x0c); | ||
940 | adv7180_write(state, ADV7180_REG_CTRL_2, 0x40); | ||
899 | } | 941 | } |
900 | 942 | ||
901 | adv7180_write(state, 0x0013, 0x00); | 943 | adv7180_write(state, 0x0013, 0x00); |
@@ -972,8 +1014,8 @@ static int adv7182_select_input(struct adv7180_state *state, unsigned int input) | |||
972 | return ret; | 1014 | return ret; |
973 | 1015 | ||
974 | /* Reset clamp circuitry - ADI recommended writes */ | 1016 | /* Reset clamp circuitry - ADI recommended writes */ |
975 | adv7180_write(state, 0x809c, 0x00); | 1017 | adv7180_write(state, ADV7180_REG_RST_CLAMP, 0x00); |
976 | adv7180_write(state, 0x809c, 0xff); | 1018 | adv7180_write(state, ADV7180_REG_RST_CLAMP, 0xff); |
977 | 1019 | ||
978 | input_type = adv7182_get_input_type(input); | 1020 | input_type = adv7182_get_input_type(input); |
979 | 1021 | ||
@@ -981,10 +1023,10 @@ static int adv7182_select_input(struct adv7180_state *state, unsigned int input) | |||
981 | case ADV7182_INPUT_TYPE_CVBS: | 1023 | case ADV7182_INPUT_TYPE_CVBS: |
982 | case ADV7182_INPUT_TYPE_DIFF_CVBS: | 1024 | case ADV7182_INPUT_TYPE_DIFF_CVBS: |
983 | /* ADI recommends to use the SH1 filter */ | 1025 | /* ADI recommends to use the SH1 filter */ |
984 | adv7180_write(state, 0x0017, 0x41); | 1026 | adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x41); |
985 | break; | 1027 | break; |
986 | default: | 1028 | default: |
987 | adv7180_write(state, 0x0017, 0x01); | 1029 | adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x01); |
988 | break; | 1030 | break; |
989 | } | 1031 | } |
990 | 1032 | ||
@@ -994,21 +1036,21 @@ static int adv7182_select_input(struct adv7180_state *state, unsigned int input) | |||
994 | lbias = adv7182_lbias_settings[input_type]; | 1036 | lbias = adv7182_lbias_settings[input_type]; |
995 | 1037 | ||
996 | for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++) | 1038 | for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++) |
997 | adv7180_write(state, 0x0052 + i, lbias[i]); | 1039 | adv7180_write(state, ADV7180_REG_CVBS_TRIM + i, lbias[i]); |
998 | 1040 | ||
999 | if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) { | 1041 | if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) { |
1000 | /* ADI required writes to make differential CVBS work */ | 1042 | /* ADI required writes to make differential CVBS work */ |
1001 | adv7180_write(state, 0x005f, 0xa8); | 1043 | adv7180_write(state, ADV7180_REG_RES_CIR, 0xa8); |
1002 | adv7180_write(state, 0x005a, 0x90); | 1044 | adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0x90); |
1003 | adv7180_write(state, 0x0060, 0xb0); | 1045 | adv7180_write(state, ADV7180_REG_DIFF_MODE, 0xb0); |
1004 | adv7180_write(state, 0x80b6, 0x08); | 1046 | adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x08); |
1005 | adv7180_write(state, 0x80c0, 0xa0); | 1047 | adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0xa0); |
1006 | } else { | 1048 | } else { |
1007 | adv7180_write(state, 0x005f, 0xf0); | 1049 | adv7180_write(state, ADV7180_REG_RES_CIR, 0xf0); |
1008 | adv7180_write(state, 0x005a, 0xd0); | 1050 | adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0xd0); |
1009 | adv7180_write(state, 0x0060, 0x10); | 1051 | adv7180_write(state, ADV7180_REG_DIFF_MODE, 0x10); |
1010 | adv7180_write(state, 0x80b6, 0x9c); | 1052 | adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x9c); |
1011 | adv7180_write(state, 0x80c0, 0x00); | 1053 | adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0x00); |
1012 | } | 1054 | } |
1013 | 1055 | ||
1014 | return 0; | 1056 | return 0; |
@@ -1185,6 +1227,8 @@ static int init_device(struct adv7180_state *state) | |||
1185 | 1227 | ||
1186 | mutex_lock(&state->mutex); | 1228 | mutex_lock(&state->mutex); |
1187 | 1229 | ||
1230 | adv7180_set_power_pin(state, true); | ||
1231 | |||
1188 | adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); | 1232 | adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); |
1189 | usleep_range(5000, 10000); | 1233 | usleep_range(5000, 10000); |
1190 | 1234 | ||
@@ -1254,6 +1298,14 @@ static int adv7180_probe(struct i2c_client *client, | |||
1254 | state->field = V4L2_FIELD_INTERLACED; | 1298 | state->field = V4L2_FIELD_INTERLACED; |
1255 | state->chip_info = (struct adv7180_chip_info *)id->driver_data; | 1299 | state->chip_info = (struct adv7180_chip_info *)id->driver_data; |
1256 | 1300 | ||
1301 | state->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", | ||
1302 | GPIOD_OUT_HIGH); | ||
1303 | if (IS_ERR(state->pwdn_gpio)) { | ||
1304 | ret = PTR_ERR(state->pwdn_gpio); | ||
1305 | v4l_err(client, "request for power pin failed: %d\n", ret); | ||
1306 | return ret; | ||
1307 | } | ||
1308 | |||
1257 | if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { | 1309 | if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { |
1258 | state->csi_client = i2c_new_dummy(client->adapter, | 1310 | state->csi_client = i2c_new_dummy(client->adapter, |
1259 | ADV7180_DEFAULT_CSI_I2C_ADDR); | 1311 | ADV7180_DEFAULT_CSI_I2C_ADDR); |
@@ -1345,6 +1397,8 @@ static int adv7180_remove(struct i2c_client *client) | |||
1345 | if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) | 1397 | if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) |
1346 | i2c_unregister_device(state->csi_client); | 1398 | i2c_unregister_device(state->csi_client); |
1347 | 1399 | ||
1400 | adv7180_set_power_pin(state, false); | ||
1401 | |||
1348 | mutex_destroy(&state->mutex); | 1402 | mutex_destroy(&state->mutex); |
1349 | 1403 | ||
1350 | return 0; | 1404 | return 0; |
diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index 2bec737881e9..04eecda74d66 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c | |||
@@ -644,7 +644,6 @@ MODULE_DEVICE_TABLE(i2c, adv7183_id); | |||
644 | 644 | ||
645 | static struct i2c_driver adv7183_driver = { | 645 | static struct i2c_driver adv7183_driver = { |
646 | .driver = { | 646 | .driver = { |
647 | .owner = THIS_MODULE, | ||
648 | .name = "adv7183", | 647 | .name = "adv7183", |
649 | }, | 648 | }, |
650 | .probe = adv7183_probe, | 649 | .probe = adv7183_probe, |
diff --git a/drivers/media/i2c/adv7393.c b/drivers/media/i2c/adv7393.c index 76d987476e35..f19ad4ecd11e 100644 --- a/drivers/media/i2c/adv7393.c +++ b/drivers/media/i2c/adv7393.c | |||
@@ -456,7 +456,6 @@ MODULE_DEVICE_TABLE(i2c, adv7393_id); | |||
456 | 456 | ||
457 | static struct i2c_driver adv7393_driver = { | 457 | static struct i2c_driver adv7393_driver = { |
458 | .driver = { | 458 | .driver = { |
459 | .owner = THIS_MODULE, | ||
460 | .name = "adv7393", | 459 | .name = "adv7393", |
461 | }, | 460 | }, |
462 | .probe = adv7393_probe, | 461 | .probe = adv7393_probe, |
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index 53030d631653..5ba0f21bcfe4 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c | |||
@@ -1898,6 +1898,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * | |||
1898 | state->i2c_cec_addr >> 1); | 1898 | state->i2c_cec_addr >> 1); |
1899 | if (state->i2c_cec == NULL) { | 1899 | if (state->i2c_cec == NULL) { |
1900 | v4l2_err(sd, "failed to register cec i2c client\n"); | 1900 | v4l2_err(sd, "failed to register cec i2c client\n"); |
1901 | err = -ENOMEM; | ||
1901 | goto err_unreg_edid; | 1902 | goto err_unreg_edid; |
1902 | } | 1903 | } |
1903 | adv7511_wr(sd, 0xe2, 0x00); /* power up cec section */ | 1904 | adv7511_wr(sd, 0xe2, 0x00); /* power up cec section */ |
diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c index d9f2b6b76d59..3a795dcb7d8e 100644 --- a/drivers/media/i2c/ak881x.c +++ b/drivers/media/i2c/ak881x.c | |||
@@ -124,21 +124,27 @@ static int ak881x_enum_mbus_code(struct v4l2_subdev *sd, | |||
124 | return 0; | 124 | return 0; |
125 | } | 125 | } |
126 | 126 | ||
127 | static int ak881x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | 127 | static int ak881x_get_selection(struct v4l2_subdev *sd, |
128 | struct v4l2_subdev_pad_config *cfg, | ||
129 | struct v4l2_subdev_selection *sel) | ||
128 | { | 130 | { |
129 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 131 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
130 | struct ak881x *ak881x = to_ak881x(client); | 132 | struct ak881x *ak881x = to_ak881x(client); |
131 | 133 | ||
132 | a->bounds.left = 0; | 134 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
133 | a->bounds.top = 0; | 135 | return -EINVAL; |
134 | a->bounds.width = 720; | ||
135 | a->bounds.height = ak881x->lines; | ||
136 | a->defrect = a->bounds; | ||
137 | a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
138 | a->pixelaspect.numerator = 1; | ||
139 | a->pixelaspect.denominator = 1; | ||
140 | 136 | ||
141 | return 0; | 137 | switch (sel->target) { |
138 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
139 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
140 | sel->r.left = 0; | ||
141 | sel->r.top = 0; | ||
142 | sel->r.width = 720; | ||
143 | sel->r.height = ak881x->lines; | ||
144 | return 0; | ||
145 | default: | ||
146 | return -EINVAL; | ||
147 | } | ||
142 | } | 148 | } |
143 | 149 | ||
144 | static int ak881x_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) | 150 | static int ak881x_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) |
@@ -207,13 +213,13 @@ static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = { | |||
207 | }; | 213 | }; |
208 | 214 | ||
209 | static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = { | 215 | static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = { |
210 | .cropcap = ak881x_cropcap, | ||
211 | .s_std_output = ak881x_s_std_output, | 216 | .s_std_output = ak881x_s_std_output, |
212 | .s_stream = ak881x_s_stream, | 217 | .s_stream = ak881x_s_stream, |
213 | }; | 218 | }; |
214 | 219 | ||
215 | static const struct v4l2_subdev_pad_ops ak881x_subdev_pad_ops = { | 220 | static const struct v4l2_subdev_pad_ops ak881x_subdev_pad_ops = { |
216 | .enum_mbus_code = ak881x_enum_mbus_code, | 221 | .enum_mbus_code = ak881x_enum_mbus_code, |
222 | .get_selection = ak881x_get_selection, | ||
217 | .set_fmt = ak881x_fill_fmt, | 223 | .set_fmt = ak881x_fill_fmt, |
218 | .get_fmt = ak881x_fill_fmt, | 224 | .get_fmt = ak881x_fill_fmt, |
219 | }; | 225 | }; |
diff --git a/drivers/media/i2c/cs3308.c b/drivers/media/i2c/cs3308.c index d28b4f37fe5f..7da5f69cace6 100644 --- a/drivers/media/i2c/cs3308.c +++ b/drivers/media/i2c/cs3308.c | |||
@@ -127,7 +127,6 @@ MODULE_DEVICE_TABLE(i2c, cs3308_id); | |||
127 | 127 | ||
128 | static struct i2c_driver cs3308_driver = { | 128 | static struct i2c_driver cs3308_driver = { |
129 | .driver = { | 129 | .driver = { |
130 | .owner = THIS_MODULE, | ||
131 | .name = "cs3308", | 130 | .name = "cs3308", |
132 | }, | 131 | }, |
133 | .probe = cs3308_probe, | 132 | .probe = cs3308_probe, |
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index bf82726fd3f4..f95a6bc839d5 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c | |||
@@ -35,6 +35,7 @@ | |||
35 | * | 35 | * |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include <asm/unaligned.h> | ||
38 | #include <linux/module.h> | 39 | #include <linux/module.h> |
39 | #include <linux/init.h> | 40 | #include <linux/init.h> |
40 | #include <linux/kernel.h> | 41 | #include <linux/kernel.h> |
@@ -63,51 +64,80 @@ module_param(debug, int, 0644); /* debug level (0,1,2) */ | |||
63 | /* ----------------------------------------------------------------------- */ | 64 | /* ----------------------------------------------------------------------- */ |
64 | 65 | ||
65 | static int get_key_haup_common(struct IR_i2c *ir, enum rc_type *protocol, | 66 | static int get_key_haup_common(struct IR_i2c *ir, enum rc_type *protocol, |
66 | u32 *scancode, u8 *ptoggle, int size, int offset) | 67 | u32 *scancode, u8 *ptoggle, int size) |
67 | { | 68 | { |
68 | unsigned char buf[6]; | 69 | unsigned char buf[6]; |
69 | int start, range, toggle, dev, code, ircode; | 70 | int start, range, toggle, dev, code, ircode, vendor; |
70 | 71 | ||
71 | /* poll IR chip */ | 72 | /* poll IR chip */ |
72 | if (size != i2c_master_recv(ir->c, buf, size)) | 73 | if (size != i2c_master_recv(ir->c, buf, size)) |
73 | return -EIO; | 74 | return -EIO; |
74 | 75 | ||
75 | /* split rc5 data block ... */ | 76 | if (buf[0] & 0x80) { |
76 | start = (buf[offset] >> 7) & 1; | 77 | int offset = (size == 6) ? 3 : 0; |
77 | range = (buf[offset] >> 6) & 1; | ||
78 | toggle = (buf[offset] >> 5) & 1; | ||
79 | dev = buf[offset] & 0x1f; | ||
80 | code = (buf[offset+1] >> 2) & 0x3f; | ||
81 | 78 | ||
82 | /* rc5 has two start bits | 79 | /* split rc5 data block ... */ |
83 | * the first bit must be one | 80 | start = (buf[offset] >> 7) & 1; |
84 | * the second bit defines the command range (1 = 0-63, 0 = 64 - 127) | 81 | range = (buf[offset] >> 6) & 1; |
85 | */ | 82 | toggle = (buf[offset] >> 5) & 1; |
86 | if (!start) | 83 | dev = buf[offset] & 0x1f; |
87 | /* no key pressed */ | 84 | code = (buf[offset+1] >> 2) & 0x3f; |
88 | return 0; | ||
89 | 85 | ||
90 | /* filter out invalid key presses */ | 86 | /* rc5 has two start bits |
91 | ircode = (start << 12) | (toggle << 11) | (dev << 6) | code; | 87 | * the first bit must be one |
92 | if ((ircode & 0x1fff) == 0x1fff) | 88 | * the second bit defines the command range: |
93 | return 0; | 89 | * 1 = 0-63, 0 = 64 - 127 |
90 | */ | ||
91 | if (!start) | ||
92 | /* no key pressed */ | ||
93 | return 0; | ||
94 | 94 | ||
95 | if (!range) | 95 | /* filter out invalid key presses */ |
96 | code += 64; | 96 | ircode = (start << 12) | (toggle << 11) | (dev << 6) | code; |
97 | if ((ircode & 0x1fff) == 0x1fff) | ||
98 | return 0; | ||
97 | 99 | ||
98 | dprintk(1,"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", | 100 | if (!range) |
99 | start, range, toggle, dev, code); | 101 | code += 64; |
100 | 102 | ||
101 | *protocol = RC_TYPE_RC5; | 103 | dprintk(1, "ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", |
102 | *scancode = RC_SCANCODE_RC5(dev, code); | 104 | start, range, toggle, dev, code); |
103 | *ptoggle = toggle; | 105 | |
104 | return 1; | 106 | *protocol = RC_TYPE_RC5; |
107 | *scancode = RC_SCANCODE_RC5(dev, code); | ||
108 | *ptoggle = toggle; | ||
109 | |||
110 | return 1; | ||
111 | } else if (size == 6 && (buf[0] & 0x40)) { | ||
112 | code = buf[4]; | ||
113 | dev = buf[3]; | ||
114 | vendor = get_unaligned_be16(buf + 1); | ||
115 | |||
116 | if (vendor == 0x800f) { | ||
117 | *ptoggle = (dev & 0x80) != 0; | ||
118 | *protocol = RC_TYPE_RC6_MCE; | ||
119 | dev &= 0x7f; | ||
120 | dprintk(1, "ir hauppauge (rc6-mce): t%d vendor=%d dev=%d code=%d\n", | ||
121 | toggle, vendor, dev, code); | ||
122 | } else { | ||
123 | *ptoggle = 0; | ||
124 | *protocol = RC_TYPE_RC6_6A_32; | ||
125 | dprintk(1, "ir hauppauge (rc6-6a-32): vendor=%d dev=%d code=%d\n", | ||
126 | vendor, dev, code); | ||
127 | } | ||
128 | |||
129 | *scancode = RC_SCANCODE_RC6_6A(vendor, dev, code); | ||
130 | |||
131 | return 1; | ||
132 | } | ||
133 | |||
134 | return 0; | ||
105 | } | 135 | } |
106 | 136 | ||
107 | static int get_key_haup(struct IR_i2c *ir, enum rc_type *protocol, | 137 | static int get_key_haup(struct IR_i2c *ir, enum rc_type *protocol, |
108 | u32 *scancode, u8 *toggle) | 138 | u32 *scancode, u8 *toggle) |
109 | { | 139 | { |
110 | return get_key_haup_common (ir, protocol, scancode, toggle, 3, 0); | 140 | return get_key_haup_common(ir, protocol, scancode, toggle, 3); |
111 | } | 141 | } |
112 | 142 | ||
113 | static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_type *protocol, | 143 | static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_type *protocol, |
@@ -126,7 +156,7 @@ static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_type *protocol, | |||
126 | if (ret != 1) | 156 | if (ret != 1) |
127 | return (ret < 0) ? ret : -EINVAL; | 157 | return (ret < 0) ? ret : -EINVAL; |
128 | 158 | ||
129 | return get_key_haup_common(ir, protocol, scancode, toggle, 6, 3); | 159 | return get_key_haup_common(ir, protocol, scancode, toggle, 6); |
130 | } | 160 | } |
131 | 161 | ||
132 | static int get_key_pixelview(struct IR_i2c *ir, enum rc_type *protocol, | 162 | static int get_key_pixelview(struct IR_i2c *ir, enum rc_type *protocol, |
@@ -347,7 +377,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
347 | case 0x71: | 377 | case 0x71: |
348 | name = "Hauppauge/Zilog Z8"; | 378 | name = "Hauppauge/Zilog Z8"; |
349 | ir->get_key = get_key_haup_xvr; | 379 | ir->get_key = get_key_haup_xvr; |
350 | rc_type = RC_BIT_RC5; | 380 | rc_type = RC_BIT_RC5 | RC_BIT_RC6_MCE | RC_BIT_RC6_6A_32; |
351 | ir_codes = RC_MAP_HAUPPAUGE; | 381 | ir_codes = RC_MAP_HAUPPAUGE; |
352 | break; | 382 | break; |
353 | } | 383 | } |
diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/mt9m111.c index 6dfaead6aaa8..72e71b762827 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c | |||
@@ -16,10 +16,11 @@ | |||
16 | #include <linux/v4l2-mediabus.h> | 16 | #include <linux/v4l2-mediabus.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | 18 | ||
19 | #include <media/soc_camera.h> | 19 | #include <media/v4l2-async.h> |
20 | #include <media/v4l2-clk.h> | 20 | #include <media/v4l2-clk.h> |
21 | #include <media/v4l2-common.h> | 21 | #include <media/v4l2-common.h> |
22 | #include <media/v4l2-ctrls.h> | 22 | #include <media/v4l2-ctrls.h> |
23 | #include <media/v4l2-device.h> | ||
23 | 24 | ||
24 | /* | 25 | /* |
25 | * MT9M111, MT9M112 and MT9M131: | 26 | * MT9M111, MT9M112 and MT9M131: |
@@ -187,10 +188,10 @@ struct mt9m111_datafmt { | |||
187 | }; | 188 | }; |
188 | 189 | ||
189 | static const struct mt9m111_datafmt mt9m111_colour_fmts[] = { | 190 | static const struct mt9m111_datafmt mt9m111_colour_fmts[] = { |
190 | {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}, | 191 | {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB}, |
191 | {MEDIA_BUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG}, | 192 | {MEDIA_BUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_SRGB}, |
192 | {MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG}, | 193 | {MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB}, |
193 | {MEDIA_BUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG}, | 194 | {MEDIA_BUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_SRGB}, |
194 | {MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, | 195 | {MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, |
195 | {MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB}, | 196 | {MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB}, |
196 | {MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB}, | 197 | {MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB}, |
@@ -383,30 +384,36 @@ static int mt9m111_reset(struct mt9m111 *mt9m111) | |||
383 | return ret; | 384 | return ret; |
384 | } | 385 | } |
385 | 386 | ||
386 | static int mt9m111_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | 387 | static int mt9m111_set_selection(struct v4l2_subdev *sd, |
388 | struct v4l2_subdev_pad_config *cfg, | ||
389 | struct v4l2_subdev_selection *sel) | ||
387 | { | 390 | { |
388 | struct v4l2_rect rect = a->c; | 391 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
389 | struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); | 392 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
393 | struct v4l2_rect rect = sel->r; | ||
390 | int width, height; | 394 | int width, height; |
391 | int ret; | 395 | int ret, align = 0; |
392 | 396 | ||
393 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 397 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || |
398 | sel->target != V4L2_SEL_TGT_CROP) | ||
394 | return -EINVAL; | 399 | return -EINVAL; |
395 | 400 | ||
396 | if (mt9m111->fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 || | 401 | if (mt9m111->fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 || |
397 | mt9m111->fmt->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) { | 402 | mt9m111->fmt->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) { |
398 | /* Bayer format - even size lengths */ | 403 | /* Bayer format - even size lengths */ |
399 | rect.width = ALIGN(rect.width, 2); | 404 | align = 1; |
400 | rect.height = ALIGN(rect.height, 2); | ||
401 | /* Let the user play with the starting pixel */ | 405 | /* Let the user play with the starting pixel */ |
402 | } | 406 | } |
403 | 407 | ||
404 | /* FIXME: the datasheet doesn't specify minimum sizes */ | 408 | /* FIXME: the datasheet doesn't specify minimum sizes */ |
405 | soc_camera_limit_side(&rect.left, &rect.width, | 409 | v4l_bound_align_image(&rect.width, 2, MT9M111_MAX_WIDTH, align, |
406 | MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH); | 410 | &rect.height, 2, MT9M111_MAX_HEIGHT, align, 0); |
407 | 411 | rect.left = clamp(rect.left, MT9M111_MIN_DARK_COLS, | |
408 | soc_camera_limit_side(&rect.top, &rect.height, | 412 | MT9M111_MIN_DARK_COLS + MT9M111_MAX_WIDTH - |
409 | MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT); | 413 | (__s32)rect.width); |
414 | rect.top = clamp(rect.top, MT9M111_MIN_DARK_ROWS, | ||
415 | MT9M111_MIN_DARK_ROWS + MT9M111_MAX_HEIGHT - | ||
416 | (__s32)rect.height); | ||
410 | 417 | ||
411 | width = min(mt9m111->width, rect.width); | 418 | width = min(mt9m111->width, rect.width); |
412 | height = min(mt9m111->height, rect.height); | 419 | height = min(mt9m111->height, rect.height); |
@@ -421,30 +428,30 @@ static int mt9m111_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | |||
421 | return ret; | 428 | return ret; |
422 | } | 429 | } |
423 | 430 | ||
424 | static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 431 | static int mt9m111_get_selection(struct v4l2_subdev *sd, |
432 | struct v4l2_subdev_pad_config *cfg, | ||
433 | struct v4l2_subdev_selection *sel) | ||
425 | { | 434 | { |
426 | struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); | 435 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
427 | 436 | struct mt9m111 *mt9m111 = to_mt9m111(client); | |
428 | a->c = mt9m111->rect; | ||
429 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | 437 | ||
434 | static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | 438 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
435 | { | ||
436 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
437 | return -EINVAL; | 439 | return -EINVAL; |
438 | 440 | ||
439 | a->bounds.left = MT9M111_MIN_DARK_COLS; | 441 | switch (sel->target) { |
440 | a->bounds.top = MT9M111_MIN_DARK_ROWS; | 442 | case V4L2_SEL_TGT_CROP_BOUNDS: |
441 | a->bounds.width = MT9M111_MAX_WIDTH; | 443 | case V4L2_SEL_TGT_CROP_DEFAULT: |
442 | a->bounds.height = MT9M111_MAX_HEIGHT; | 444 | sel->r.left = MT9M111_MIN_DARK_COLS; |
443 | a->defrect = a->bounds; | 445 | sel->r.top = MT9M111_MIN_DARK_ROWS; |
444 | a->pixelaspect.numerator = 1; | 446 | sel->r.width = MT9M111_MAX_WIDTH; |
445 | a->pixelaspect.denominator = 1; | 447 | sel->r.height = MT9M111_MAX_HEIGHT; |
446 | 448 | return 0; | |
447 | return 0; | 449 | case V4L2_SEL_TGT_CROP: |
450 | sel->r = mt9m111->rect; | ||
451 | return 0; | ||
452 | default: | ||
453 | return -EINVAL; | ||
454 | } | ||
448 | } | 455 | } |
449 | 456 | ||
450 | static int mt9m111_get_fmt(struct v4l2_subdev *sd, | 457 | static int mt9m111_get_fmt(struct v4l2_subdev *sd, |
@@ -775,17 +782,16 @@ static int mt9m111_init(struct mt9m111 *mt9m111) | |||
775 | static int mt9m111_power_on(struct mt9m111 *mt9m111) | 782 | static int mt9m111_power_on(struct mt9m111 *mt9m111) |
776 | { | 783 | { |
777 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | 784 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); |
778 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); | ||
779 | int ret; | 785 | int ret; |
780 | 786 | ||
781 | ret = soc_camera_power_on(&client->dev, ssdd, mt9m111->clk); | 787 | ret = v4l2_clk_enable(mt9m111->clk); |
782 | if (ret < 0) | 788 | if (ret < 0) |
783 | return ret; | 789 | return ret; |
784 | 790 | ||
785 | ret = mt9m111_resume(mt9m111); | 791 | ret = mt9m111_resume(mt9m111); |
786 | if (ret < 0) { | 792 | if (ret < 0) { |
787 | dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret); | 793 | dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret); |
788 | soc_camera_power_off(&client->dev, ssdd, mt9m111->clk); | 794 | v4l2_clk_disable(mt9m111->clk); |
789 | } | 795 | } |
790 | 796 | ||
791 | return ret; | 797 | return ret; |
@@ -793,11 +799,8 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111) | |||
793 | 799 | ||
794 | static void mt9m111_power_off(struct mt9m111 *mt9m111) | 800 | static void mt9m111_power_off(struct mt9m111 *mt9m111) |
795 | { | 801 | { |
796 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | ||
797 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); | ||
798 | |||
799 | mt9m111_suspend(mt9m111); | 802 | mt9m111_suspend(mt9m111); |
800 | soc_camera_power_off(&client->dev, ssdd, mt9m111->clk); | 803 | v4l2_clk_disable(mt9m111->clk); |
801 | } | 804 | } |
802 | 805 | ||
803 | static int mt9m111_s_power(struct v4l2_subdev *sd, int on) | 806 | static int mt9m111_s_power(struct v4l2_subdev *sd, int on) |
@@ -854,27 +857,22 @@ static int mt9m111_enum_mbus_code(struct v4l2_subdev *sd, | |||
854 | static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, | 857 | static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, |
855 | struct v4l2_mbus_config *cfg) | 858 | struct v4l2_mbus_config *cfg) |
856 | { | 859 | { |
857 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
858 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); | ||
859 | |||
860 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | | 860 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | |
861 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | 861 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | |
862 | V4L2_MBUS_DATA_ACTIVE_HIGH; | 862 | V4L2_MBUS_DATA_ACTIVE_HIGH; |
863 | cfg->type = V4L2_MBUS_PARALLEL; | 863 | cfg->type = V4L2_MBUS_PARALLEL; |
864 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); | ||
865 | 864 | ||
866 | return 0; | 865 | return 0; |
867 | } | 866 | } |
868 | 867 | ||
869 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { | 868 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { |
870 | .s_crop = mt9m111_s_crop, | ||
871 | .g_crop = mt9m111_g_crop, | ||
872 | .cropcap = mt9m111_cropcap, | ||
873 | .g_mbus_config = mt9m111_g_mbus_config, | 869 | .g_mbus_config = mt9m111_g_mbus_config, |
874 | }; | 870 | }; |
875 | 871 | ||
876 | static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = { | 872 | static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = { |
877 | .enum_mbus_code = mt9m111_enum_mbus_code, | 873 | .enum_mbus_code = mt9m111_enum_mbus_code, |
874 | .get_selection = mt9m111_get_selection, | ||
875 | .set_selection = mt9m111_set_selection, | ||
878 | .get_fmt = mt9m111_get_fmt, | 876 | .get_fmt = mt9m111_get_fmt, |
879 | .set_fmt = mt9m111_set_fmt, | 877 | .set_fmt = mt9m111_set_fmt, |
880 | }; | 878 | }; |
@@ -933,20 +931,8 @@ static int mt9m111_probe(struct i2c_client *client, | |||
933 | { | 931 | { |
934 | struct mt9m111 *mt9m111; | 932 | struct mt9m111 *mt9m111; |
935 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 933 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
936 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); | ||
937 | int ret; | 934 | int ret; |
938 | 935 | ||
939 | if (client->dev.of_node) { | ||
940 | ssdd = devm_kzalloc(&client->dev, sizeof(*ssdd), GFP_KERNEL); | ||
941 | if (!ssdd) | ||
942 | return -ENOMEM; | ||
943 | client->dev.platform_data = ssdd; | ||
944 | } | ||
945 | if (!ssdd) { | ||
946 | dev_err(&client->dev, "mt9m111: driver needs platform data\n"); | ||
947 | return -EINVAL; | ||
948 | } | ||
949 | |||
950 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { | 936 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { |
951 | dev_warn(&adapter->dev, | 937 | dev_warn(&adapter->dev, |
952 | "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); | 938 | "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); |
@@ -992,10 +978,6 @@ static int mt9m111_probe(struct i2c_client *client, | |||
992 | mt9m111->lastpage = -1; | 978 | mt9m111->lastpage = -1; |
993 | mutex_init(&mt9m111->power_lock); | 979 | mutex_init(&mt9m111->power_lock); |
994 | 980 | ||
995 | ret = soc_camera_power_init(&client->dev, ssdd); | ||
996 | if (ret < 0) | ||
997 | goto out_hdlfree; | ||
998 | |||
999 | ret = mt9m111_video_probe(client); | 981 | ret = mt9m111_video_probe(client); |
1000 | if (ret < 0) | 982 | if (ret < 0) |
1001 | goto out_hdlfree; | 983 | goto out_hdlfree; |
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index be5a7fd4f076..502c72238a4a 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/videodev2.h> | 23 | #include <linux/videodev2.h> |
24 | 24 | ||
25 | #include <media/media-entity.h> | 25 | #include <media/media-entity.h> |
26 | #include <media/v4l2-async.h> | ||
26 | #include <media/v4l2-ctrls.h> | 27 | #include <media/v4l2-ctrls.h> |
27 | #include <media/v4l2-device.h> | 28 | #include <media/v4l2-device.h> |
28 | #include <media/v4l2-event.h> | 29 | #include <media/v4l2-event.h> |
@@ -1520,6 +1521,10 @@ static int ov965x_probe(struct i2c_client *client, | |||
1520 | /* Update exposure time min/max to match frame format */ | 1521 | /* Update exposure time min/max to match frame format */ |
1521 | ov965x_update_exposure_ctrl(ov965x); | 1522 | ov965x_update_exposure_ctrl(ov965x); |
1522 | 1523 | ||
1524 | ret = v4l2_async_register_subdev(sd); | ||
1525 | if (ret < 0) | ||
1526 | goto err_ctrls; | ||
1527 | |||
1523 | return 0; | 1528 | return 0; |
1524 | err_ctrls: | 1529 | err_ctrls: |
1525 | v4l2_ctrl_handler_free(sd->ctrl_handler); | 1530 | v4l2_ctrl_handler_free(sd->ctrl_handler); |
@@ -1532,7 +1537,7 @@ static int ov965x_remove(struct i2c_client *client) | |||
1532 | { | 1537 | { |
1533 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 1538 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
1534 | 1539 | ||
1535 | v4l2_device_unregister_subdev(sd); | 1540 | v4l2_async_unregister_subdev(sd); |
1536 | v4l2_ctrl_handler_free(sd->ctrl_handler); | 1541 | v4l2_ctrl_handler_free(sd->ctrl_handler); |
1537 | media_entity_cleanup(&sd->entity); | 1542 | media_entity_cleanup(&sd->entity); |
1538 | 1543 | ||
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 08af58fb8e7d..3844853ab0a0 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c | |||
@@ -1706,7 +1706,7 @@ static int s5c73m3_probe(struct i2c_client *client, | |||
1706 | state->oif_pads[OIF_ISP_PAD].flags = MEDIA_PAD_FL_SINK; | 1706 | state->oif_pads[OIF_ISP_PAD].flags = MEDIA_PAD_FL_SINK; |
1707 | state->oif_pads[OIF_JPEG_PAD].flags = MEDIA_PAD_FL_SINK; | 1707 | state->oif_pads[OIF_JPEG_PAD].flags = MEDIA_PAD_FL_SINK; |
1708 | state->oif_pads[OIF_SOURCE_PAD].flags = MEDIA_PAD_FL_SOURCE; | 1708 | state->oif_pads[OIF_SOURCE_PAD].flags = MEDIA_PAD_FL_SOURCE; |
1709 | oif_sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; | 1709 | oif_sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; |
1710 | 1710 | ||
1711 | ret = media_entity_pads_init(&oif_sd->entity, OIF_NUM_PADS, | 1711 | ret = media_entity_pads_init(&oif_sd->entity, OIF_NUM_PADS, |
1712 | state->oif_pads); | 1712 | state->oif_pads); |
diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c index 8a0f22da590f..6ebcf254989a 100644 --- a/drivers/media/i2c/s5k4ecgx.c +++ b/drivers/media/i2c/s5k4ecgx.c | |||
@@ -1019,7 +1019,6 @@ MODULE_DEVICE_TABLE(i2c, s5k4ecgx_id); | |||
1019 | 1019 | ||
1020 | static struct i2c_driver v4l2_i2c_driver = { | 1020 | static struct i2c_driver v4l2_i2c_driver = { |
1021 | .driver = { | 1021 | .driver = { |
1022 | .owner = THIS_MODULE, | ||
1023 | .name = S5K4ECGX_DRIVER_NAME, | 1022 | .name = S5K4ECGX_DRIVER_NAME, |
1024 | }, | 1023 | }, |
1025 | .probe = s5k4ecgx_probe, | 1024 | .probe = s5k4ecgx_probe, |
diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index cbe4711e9b31..769964057881 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c | |||
@@ -331,6 +331,7 @@ static int s5k6a3_probe(struct i2c_client *client, | |||
331 | sensor->format.width = S5K6A3_DEFAULT_WIDTH; | 331 | sensor->format.width = S5K6A3_DEFAULT_WIDTH; |
332 | sensor->format.height = S5K6A3_DEFAULT_HEIGHT; | 332 | sensor->format.height = S5K6A3_DEFAULT_HEIGHT; |
333 | 333 | ||
334 | sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; | ||
334 | sensor->pad.flags = MEDIA_PAD_FL_SOURCE; | 335 | sensor->pad.flags = MEDIA_PAD_FL_SOURCE; |
335 | ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad); | 336 | ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad); |
336 | if (ret < 0) | 337 | if (ret < 0) |
@@ -376,7 +377,6 @@ static struct i2c_driver s5k6a3_driver = { | |||
376 | .driver = { | 377 | .driver = { |
377 | .of_match_table = of_match_ptr(s5k6a3_of_match), | 378 | .of_match_table = of_match_ptr(s5k6a3_of_match), |
378 | .name = S5K6A3_DRV_NAME, | 379 | .name = S5K6A3_DRV_NAME, |
379 | .owner = THIS_MODULE, | ||
380 | }, | 380 | }, |
381 | .probe = s5k6a3_probe, | 381 | .probe = s5k6a3_probe, |
382 | .remove = s5k6a3_remove, | 382 | .remove = s5k6a3_remove, |
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index d08ab6c8357c..44f8c7e10a35 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c | |||
@@ -24,8 +24,8 @@ | |||
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
26 | #include <linux/gpio.h> | 26 | #include <linux/gpio.h> |
27 | #include <linux/gpio/consumer.h> | ||
27 | #include <linux/module.h> | 28 | #include <linux/module.h> |
28 | #include <linux/of_gpio.h> | ||
29 | #include <linux/regulator/consumer.h> | 29 | #include <linux/regulator/consumer.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/smiapp.h> | 31 | #include <linux/smiapp.h> |
@@ -328,6 +328,14 @@ static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor) | |||
328 | * orders must be defined. | 328 | * orders must be defined. |
329 | */ | 329 | */ |
330 | static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = { | 330 | static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = { |
331 | { MEDIA_BUS_FMT_SGRBG16_1X16, 16, 16, SMIAPP_PIXEL_ORDER_GRBG, }, | ||
332 | { MEDIA_BUS_FMT_SRGGB16_1X16, 16, 16, SMIAPP_PIXEL_ORDER_RGGB, }, | ||
333 | { MEDIA_BUS_FMT_SBGGR16_1X16, 16, 16, SMIAPP_PIXEL_ORDER_BGGR, }, | ||
334 | { MEDIA_BUS_FMT_SGBRG16_1X16, 16, 16, SMIAPP_PIXEL_ORDER_GBRG, }, | ||
335 | { MEDIA_BUS_FMT_SGRBG14_1X14, 14, 14, SMIAPP_PIXEL_ORDER_GRBG, }, | ||
336 | { MEDIA_BUS_FMT_SRGGB14_1X14, 14, 14, SMIAPP_PIXEL_ORDER_RGGB, }, | ||
337 | { MEDIA_BUS_FMT_SBGGR14_1X14, 14, 14, SMIAPP_PIXEL_ORDER_BGGR, }, | ||
338 | { MEDIA_BUS_FMT_SGBRG14_1X14, 14, 14, SMIAPP_PIXEL_ORDER_GBRG, }, | ||
331 | { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, }, | 339 | { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, }, |
332 | { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, }, | 340 | { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, }, |
333 | { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, }, | 341 | { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, }, |
@@ -625,12 +633,12 @@ static int smiapp_init_late_controls(struct smiapp_sensor *sensor) | |||
625 | 0, max_value, 1, max_value); | 633 | 0, max_value, 1, max_value); |
626 | } | 634 | } |
627 | 635 | ||
628 | for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++); | 636 | for (max = 0; sensor->hwcfg->op_sys_clock[max + 1]; max++); |
629 | 637 | ||
630 | sensor->link_freq = v4l2_ctrl_new_int_menu( | 638 | sensor->link_freq = v4l2_ctrl_new_int_menu( |
631 | &sensor->src->ctrl_handler, &smiapp_ctrl_ops, | 639 | &sensor->src->ctrl_handler, &smiapp_ctrl_ops, |
632 | V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs), | 640 | V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs), |
633 | __ffs(*valid_link_freqs), sensor->platform_data->op_sys_clock); | 641 | __ffs(*valid_link_freqs), sensor->hwcfg->op_sys_clock); |
634 | 642 | ||
635 | return sensor->src->ctrl_handler.error; | 643 | return sensor->src->ctrl_handler.error; |
636 | } | 644 | } |
@@ -833,8 +841,8 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) | |||
833 | 841 | ||
834 | pll->bits_per_pixel = f->compressed; | 842 | pll->bits_per_pixel = f->compressed; |
835 | 843 | ||
836 | for (j = 0; sensor->platform_data->op_sys_clock[j]; j++) { | 844 | for (j = 0; sensor->hwcfg->op_sys_clock[j]; j++) { |
837 | pll->link_freq = sensor->platform_data->op_sys_clock[j]; | 845 | pll->link_freq = sensor->hwcfg->op_sys_clock[j]; |
838 | 846 | ||
839 | rval = smiapp_pll_try(sensor, pll); | 847 | rval = smiapp_pll_try(sensor, pll); |
840 | dev_dbg(&client->dev, "link freq %u Hz, bpp %u %s\n", | 848 | dev_dbg(&client->dev, "link freq %u Hz, bpp %u %s\n", |
@@ -1032,22 +1040,22 @@ static int smiapp_change_cci_addr(struct smiapp_sensor *sensor) | |||
1032 | int rval; | 1040 | int rval; |
1033 | u32 val; | 1041 | u32 val; |
1034 | 1042 | ||
1035 | client->addr = sensor->platform_data->i2c_addr_dfl; | 1043 | client->addr = sensor->hwcfg->i2c_addr_dfl; |
1036 | 1044 | ||
1037 | rval = smiapp_write(sensor, | 1045 | rval = smiapp_write(sensor, |
1038 | SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, | 1046 | SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, |
1039 | sensor->platform_data->i2c_addr_alt << 1); | 1047 | sensor->hwcfg->i2c_addr_alt << 1); |
1040 | if (rval) | 1048 | if (rval) |
1041 | return rval; | 1049 | return rval; |
1042 | 1050 | ||
1043 | client->addr = sensor->platform_data->i2c_addr_alt; | 1051 | client->addr = sensor->hwcfg->i2c_addr_alt; |
1044 | 1052 | ||
1045 | /* verify addr change went ok */ | 1053 | /* verify addr change went ok */ |
1046 | rval = smiapp_read(sensor, SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, &val); | 1054 | rval = smiapp_read(sensor, SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, &val); |
1047 | if (rval) | 1055 | if (rval) |
1048 | return rval; | 1056 | return rval; |
1049 | 1057 | ||
1050 | if (val != sensor->platform_data->i2c_addr_alt << 1) | 1058 | if (val != sensor->hwcfg->i2c_addr_alt << 1) |
1051 | return -ENODEV; | 1059 | return -ENODEV; |
1052 | 1060 | ||
1053 | return 0; | 1061 | return 0; |
@@ -1061,13 +1069,13 @@ static int smiapp_change_cci_addr(struct smiapp_sensor *sensor) | |||
1061 | static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor) | 1069 | static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor) |
1062 | { | 1070 | { |
1063 | struct smiapp_flash_strobe_parms *strobe_setup; | 1071 | struct smiapp_flash_strobe_parms *strobe_setup; |
1064 | unsigned int ext_freq = sensor->platform_data->ext_clk; | 1072 | unsigned int ext_freq = sensor->hwcfg->ext_clk; |
1065 | u32 tmp; | 1073 | u32 tmp; |
1066 | u32 strobe_adjustment; | 1074 | u32 strobe_adjustment; |
1067 | u32 strobe_width_high_rs; | 1075 | u32 strobe_width_high_rs; |
1068 | int rval; | 1076 | int rval; |
1069 | 1077 | ||
1070 | strobe_setup = sensor->platform_data->strobe_setup; | 1078 | strobe_setup = sensor->hwcfg->strobe_setup; |
1071 | 1079 | ||
1072 | /* | 1080 | /* |
1073 | * How to calculate registers related to strobe length. Please | 1081 | * How to calculate registers related to strobe length. Please |
@@ -1179,7 +1187,7 @@ static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor) | |||
1179 | strobe_setup->trigger); | 1187 | strobe_setup->trigger); |
1180 | 1188 | ||
1181 | out: | 1189 | out: |
1182 | sensor->platform_data->strobe_setup->trigger = 0; | 1190 | sensor->hwcfg->strobe_setup->trigger = 0; |
1183 | 1191 | ||
1184 | return rval; | 1192 | return rval; |
1185 | } | 1193 | } |
@@ -1201,21 +1209,16 @@ static int smiapp_power_on(struct smiapp_sensor *sensor) | |||
1201 | } | 1209 | } |
1202 | usleep_range(1000, 1000); | 1210 | usleep_range(1000, 1000); |
1203 | 1211 | ||
1204 | if (sensor->platform_data->set_xclk) | 1212 | rval = clk_prepare_enable(sensor->ext_clk); |
1205 | rval = sensor->platform_data->set_xclk( | ||
1206 | &sensor->src->sd, sensor->platform_data->ext_clk); | ||
1207 | else | ||
1208 | rval = clk_prepare_enable(sensor->ext_clk); | ||
1209 | if (rval < 0) { | 1213 | if (rval < 0) { |
1210 | dev_dbg(&client->dev, "failed to enable xclk\n"); | 1214 | dev_dbg(&client->dev, "failed to enable xclk\n"); |
1211 | goto out_xclk_fail; | 1215 | goto out_xclk_fail; |
1212 | } | 1216 | } |
1213 | usleep_range(1000, 1000); | 1217 | usleep_range(1000, 1000); |
1214 | 1218 | ||
1215 | if (gpio_is_valid(sensor->platform_data->xshutdown)) | 1219 | gpiod_set_value(sensor->xshutdown, 1); |
1216 | gpio_set_value(sensor->platform_data->xshutdown, 1); | ||
1217 | 1220 | ||
1218 | sleep = SMIAPP_RESET_DELAY(sensor->platform_data->ext_clk); | 1221 | sleep = SMIAPP_RESET_DELAY(sensor->hwcfg->ext_clk); |
1219 | usleep_range(sleep, sleep); | 1222 | usleep_range(sleep, sleep); |
1220 | 1223 | ||
1221 | /* | 1224 | /* |
@@ -1229,7 +1232,7 @@ static int smiapp_power_on(struct smiapp_sensor *sensor) | |||
1229 | * is found. | 1232 | * is found. |
1230 | */ | 1233 | */ |
1231 | 1234 | ||
1232 | if (sensor->platform_data->i2c_addr_alt) { | 1235 | if (sensor->hwcfg->i2c_addr_alt) { |
1233 | rval = smiapp_change_cci_addr(sensor); | 1236 | rval = smiapp_change_cci_addr(sensor); |
1234 | if (rval) { | 1237 | if (rval) { |
1235 | dev_err(&client->dev, "cci address change error\n"); | 1238 | dev_err(&client->dev, "cci address change error\n"); |
@@ -1244,7 +1247,7 @@ static int smiapp_power_on(struct smiapp_sensor *sensor) | |||
1244 | goto out_cci_addr_fail; | 1247 | goto out_cci_addr_fail; |
1245 | } | 1248 | } |
1246 | 1249 | ||
1247 | if (sensor->platform_data->i2c_addr_alt) { | 1250 | if (sensor->hwcfg->i2c_addr_alt) { |
1248 | rval = smiapp_change_cci_addr(sensor); | 1251 | rval = smiapp_change_cci_addr(sensor); |
1249 | if (rval) { | 1252 | if (rval) { |
1250 | dev_err(&client->dev, "cci address change error\n"); | 1253 | dev_err(&client->dev, "cci address change error\n"); |
@@ -1261,14 +1264,14 @@ static int smiapp_power_on(struct smiapp_sensor *sensor) | |||
1261 | 1264 | ||
1262 | rval = smiapp_write( | 1265 | rval = smiapp_write( |
1263 | sensor, SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ, | 1266 | sensor, SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ, |
1264 | sensor->platform_data->ext_clk / (1000000 / (1 << 8))); | 1267 | sensor->hwcfg->ext_clk / (1000000 / (1 << 8))); |
1265 | if (rval) { | 1268 | if (rval) { |
1266 | dev_err(&client->dev, "extclk frequency set failed\n"); | 1269 | dev_err(&client->dev, "extclk frequency set failed\n"); |
1267 | goto out_cci_addr_fail; | 1270 | goto out_cci_addr_fail; |
1268 | } | 1271 | } |
1269 | 1272 | ||
1270 | rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_LANE_MODE, | 1273 | rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_LANE_MODE, |
1271 | sensor->platform_data->lanes - 1); | 1274 | sensor->hwcfg->lanes - 1); |
1272 | if (rval) { | 1275 | if (rval) { |
1273 | dev_err(&client->dev, "csi lane mode set failed\n"); | 1276 | dev_err(&client->dev, "csi lane mode set failed\n"); |
1274 | goto out_cci_addr_fail; | 1277 | goto out_cci_addr_fail; |
@@ -1282,7 +1285,7 @@ static int smiapp_power_on(struct smiapp_sensor *sensor) | |||
1282 | } | 1285 | } |
1283 | 1286 | ||
1284 | rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_SIGNALLING_MODE, | 1287 | rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_SIGNALLING_MODE, |
1285 | sensor->platform_data->csi_signalling_mode); | 1288 | sensor->hwcfg->csi_signalling_mode); |
1286 | if (rval) { | 1289 | if (rval) { |
1287 | dev_err(&client->dev, "csi signalling mode set failed\n"); | 1290 | dev_err(&client->dev, "csi signalling mode set failed\n"); |
1288 | goto out_cci_addr_fail; | 1291 | goto out_cci_addr_fail; |
@@ -1322,12 +1325,8 @@ static int smiapp_power_on(struct smiapp_sensor *sensor) | |||
1322 | return 0; | 1325 | return 0; |
1323 | 1326 | ||
1324 | out_cci_addr_fail: | 1327 | out_cci_addr_fail: |
1325 | if (gpio_is_valid(sensor->platform_data->xshutdown)) | 1328 | gpiod_set_value(sensor->xshutdown, 0); |
1326 | gpio_set_value(sensor->platform_data->xshutdown, 0); | 1329 | clk_disable_unprepare(sensor->ext_clk); |
1327 | if (sensor->platform_data->set_xclk) | ||
1328 | sensor->platform_data->set_xclk(&sensor->src->sd, 0); | ||
1329 | else | ||
1330 | clk_disable_unprepare(sensor->ext_clk); | ||
1331 | 1330 | ||
1332 | out_xclk_fail: | 1331 | out_xclk_fail: |
1333 | regulator_disable(sensor->vana); | 1332 | regulator_disable(sensor->vana); |
@@ -1343,17 +1342,13 @@ static void smiapp_power_off(struct smiapp_sensor *sensor) | |||
1343 | * really see a power off and next time the cci address change | 1342 | * really see a power off and next time the cci address change |
1344 | * will fail. So do a soft reset explicitly here. | 1343 | * will fail. So do a soft reset explicitly here. |
1345 | */ | 1344 | */ |
1346 | if (sensor->platform_data->i2c_addr_alt) | 1345 | if (sensor->hwcfg->i2c_addr_alt) |
1347 | smiapp_write(sensor, | 1346 | smiapp_write(sensor, |
1348 | SMIAPP_REG_U8_SOFTWARE_RESET, | 1347 | SMIAPP_REG_U8_SOFTWARE_RESET, |
1349 | SMIAPP_SOFTWARE_RESET); | 1348 | SMIAPP_SOFTWARE_RESET); |
1350 | 1349 | ||
1351 | if (gpio_is_valid(sensor->platform_data->xshutdown)) | 1350 | gpiod_set_value(sensor->xshutdown, 0); |
1352 | gpio_set_value(sensor->platform_data->xshutdown, 0); | 1351 | clk_disable_unprepare(sensor->ext_clk); |
1353 | if (sensor->platform_data->set_xclk) | ||
1354 | sensor->platform_data->set_xclk(&sensor->src->sd, 0); | ||
1355 | else | ||
1356 | clk_disable_unprepare(sensor->ext_clk); | ||
1357 | usleep_range(5000, 5000); | 1352 | usleep_range(5000, 5000); |
1358 | regulator_disable(sensor->vana); | 1353 | regulator_disable(sensor->vana); |
1359 | sensor->streaming = false; | 1354 | sensor->streaming = false; |
@@ -1491,8 +1486,8 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) | |||
1491 | if ((sensor->limits[SMIAPP_LIMIT_FLASH_MODE_CAPABILITY] & | 1486 | if ((sensor->limits[SMIAPP_LIMIT_FLASH_MODE_CAPABILITY] & |
1492 | (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE | | 1487 | (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE | |
1493 | SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) && | 1488 | SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) && |
1494 | sensor->platform_data->strobe_setup != NULL && | 1489 | sensor->hwcfg->strobe_setup != NULL && |
1495 | sensor->platform_data->strobe_setup->trigger != 0) { | 1490 | sensor->hwcfg->strobe_setup->trigger != 0) { |
1496 | rval = smiapp_setup_flash_strobe(sensor); | 1491 | rval = smiapp_setup_flash_strobe(sensor); |
1497 | if (rval) | 1492 | if (rval) |
1498 | goto out; | 1493 | goto out; |
@@ -2309,7 +2304,7 @@ smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, | |||
2309 | 2304 | ||
2310 | if (!sensor->nvm_size) { | 2305 | if (!sensor->nvm_size) { |
2311 | /* NVM not read yet - read it now */ | 2306 | /* NVM not read yet - read it now */ |
2312 | sensor->nvm_size = sensor->platform_data->nvm_size; | 2307 | sensor->nvm_size = sensor->hwcfg->nvm_size; |
2313 | if (smiapp_set_power(subdev, 1) < 0) | 2308 | if (smiapp_set_power(subdev, 1) < 0) |
2314 | return -ENODEV; | 2309 | return -ENODEV; |
2315 | if (smiapp_read_nvm(sensor, sensor->nvm)) { | 2310 | if (smiapp_read_nvm(sensor, sensor->nvm)) { |
@@ -2554,35 +2549,27 @@ static int smiapp_init(struct smiapp_sensor *sensor) | |||
2554 | return PTR_ERR(sensor->vana); | 2549 | return PTR_ERR(sensor->vana); |
2555 | } | 2550 | } |
2556 | 2551 | ||
2557 | if (!sensor->platform_data->set_xclk) { | 2552 | sensor->ext_clk = devm_clk_get(&client->dev, NULL); |
2558 | sensor->ext_clk = devm_clk_get(&client->dev, NULL); | 2553 | if (IS_ERR(sensor->ext_clk)) { |
2559 | if (IS_ERR(sensor->ext_clk)) { | 2554 | dev_err(&client->dev, "could not get clock (%ld)\n", |
2560 | dev_err(&client->dev, "could not get clock\n"); | 2555 | PTR_ERR(sensor->ext_clk)); |
2561 | return PTR_ERR(sensor->ext_clk); | 2556 | return -EPROBE_DEFER; |
2562 | } | ||
2563 | |||
2564 | rval = clk_set_rate(sensor->ext_clk, | ||
2565 | sensor->platform_data->ext_clk); | ||
2566 | if (rval < 0) { | ||
2567 | dev_err(&client->dev, | ||
2568 | "unable to set clock freq to %u\n", | ||
2569 | sensor->platform_data->ext_clk); | ||
2570 | return rval; | ||
2571 | } | ||
2572 | } | 2557 | } |
2573 | 2558 | ||
2574 | if (gpio_is_valid(sensor->platform_data->xshutdown)) { | 2559 | rval = clk_set_rate(sensor->ext_clk, |
2575 | rval = devm_gpio_request_one( | 2560 | sensor->hwcfg->ext_clk); |
2576 | &client->dev, sensor->platform_data->xshutdown, 0, | 2561 | if (rval < 0) { |
2577 | "SMIA++ xshutdown"); | 2562 | dev_err(&client->dev, |
2578 | if (rval < 0) { | 2563 | "unable to set clock freq to %u\n", |
2579 | dev_err(&client->dev, | 2564 | sensor->hwcfg->ext_clk); |
2580 | "unable to acquire reset gpio %d\n", | 2565 | return rval; |
2581 | sensor->platform_data->xshutdown); | ||
2582 | return rval; | ||
2583 | } | ||
2584 | } | 2566 | } |
2585 | 2567 | ||
2568 | sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown", | ||
2569 | GPIOD_OUT_LOW); | ||
2570 | if (IS_ERR(sensor->xshutdown)) | ||
2571 | return PTR_ERR(sensor->xshutdown); | ||
2572 | |||
2586 | rval = smiapp_power_on(sensor); | 2573 | rval = smiapp_power_on(sensor); |
2587 | if (rval) | 2574 | if (rval) |
2588 | return -ENODEV; | 2575 | return -ENODEV; |
@@ -2612,7 +2599,7 @@ static int smiapp_init(struct smiapp_sensor *sensor) | |||
2612 | * | 2599 | * |
2613 | * Rotation also changes the bayer pattern. | 2600 | * Rotation also changes the bayer pattern. |
2614 | */ | 2601 | */ |
2615 | if (sensor->platform_data->module_board_orient == | 2602 | if (sensor->hwcfg->module_board_orient == |
2616 | SMIAPP_MODULE_BOARD_ORIENT_180) | 2603 | SMIAPP_MODULE_BOARD_ORIENT_180) |
2617 | sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP | | 2604 | sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP | |
2618 | SMIAPP_IMAGE_ORIENTATION_VFLIP; | 2605 | SMIAPP_IMAGE_ORIENTATION_VFLIP; |
@@ -2661,9 +2648,9 @@ static int smiapp_init(struct smiapp_sensor *sensor) | |||
2661 | /* SMIA++ NVM initialization - it will be read from the sensor | 2648 | /* SMIA++ NVM initialization - it will be read from the sensor |
2662 | * when it is first requested by userspace. | 2649 | * when it is first requested by userspace. |
2663 | */ | 2650 | */ |
2664 | if (sensor->minfo.smiapp_version && sensor->platform_data->nvm_size) { | 2651 | if (sensor->minfo.smiapp_version && sensor->hwcfg->nvm_size) { |
2665 | sensor->nvm = devm_kzalloc(&client->dev, | 2652 | sensor->nvm = devm_kzalloc(&client->dev, |
2666 | sensor->platform_data->nvm_size, GFP_KERNEL); | 2653 | sensor->hwcfg->nvm_size, GFP_KERNEL); |
2667 | if (sensor->nvm == NULL) { | 2654 | if (sensor->nvm == NULL) { |
2668 | dev_err(&client->dev, "nvm buf allocation failed\n"); | 2655 | dev_err(&client->dev, "nvm buf allocation failed\n"); |
2669 | rval = -ENOMEM; | 2656 | rval = -ENOMEM; |
@@ -2706,8 +2693,8 @@ static int smiapp_init(struct smiapp_sensor *sensor) | |||
2706 | 2693 | ||
2707 | /* prepare PLL configuration input values */ | 2694 | /* prepare PLL configuration input values */ |
2708 | pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; | 2695 | pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; |
2709 | pll->csi2.lanes = sensor->platform_data->lanes; | 2696 | pll->csi2.lanes = sensor->hwcfg->lanes; |
2710 | pll->ext_clk_freq_hz = sensor->platform_data->ext_clk; | 2697 | pll->ext_clk_freq_hz = sensor->hwcfg->ext_clk; |
2711 | pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; | 2698 | pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; |
2712 | /* Profile 0 sensors have no separate OP clock branch. */ | 2699 | /* Profile 0 sensors have no separate OP clock branch. */ |
2713 | if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) | 2700 | if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) |
@@ -2984,9 +2971,9 @@ static int smiapp_resume(struct device *dev) | |||
2984 | 2971 | ||
2985 | #endif /* CONFIG_PM */ | 2972 | #endif /* CONFIG_PM */ |
2986 | 2973 | ||
2987 | static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) | 2974 | static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) |
2988 | { | 2975 | { |
2989 | struct smiapp_platform_data *pdata; | 2976 | struct smiapp_hwconfig *hwcfg; |
2990 | struct v4l2_of_endpoint *bus_cfg; | 2977 | struct v4l2_of_endpoint *bus_cfg; |
2991 | struct device_node *ep; | 2978 | struct device_node *ep; |
2992 | int i; | 2979 | int i; |
@@ -3003,58 +2990,55 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) | |||
3003 | if (IS_ERR(bus_cfg)) | 2990 | if (IS_ERR(bus_cfg)) |
3004 | goto out_err; | 2991 | goto out_err; |
3005 | 2992 | ||
3006 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | 2993 | hwcfg = devm_kzalloc(dev, sizeof(*hwcfg), GFP_KERNEL); |
3007 | if (!pdata) | 2994 | if (!hwcfg) |
3008 | goto out_err; | 2995 | goto out_err; |
3009 | 2996 | ||
3010 | switch (bus_cfg->bus_type) { | 2997 | switch (bus_cfg->bus_type) { |
3011 | case V4L2_MBUS_CSI2: | 2998 | case V4L2_MBUS_CSI2: |
3012 | pdata->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2; | 2999 | hwcfg->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2; |
3013 | break; | 3000 | break; |
3014 | /* FIXME: add CCP2 support. */ | 3001 | /* FIXME: add CCP2 support. */ |
3015 | default: | 3002 | default: |
3016 | goto out_err; | 3003 | goto out_err; |
3017 | } | 3004 | } |
3018 | 3005 | ||
3019 | pdata->lanes = bus_cfg->bus.mipi_csi2.num_data_lanes; | 3006 | hwcfg->lanes = bus_cfg->bus.mipi_csi2.num_data_lanes; |
3020 | dev_dbg(dev, "lanes %u\n", pdata->lanes); | 3007 | dev_dbg(dev, "lanes %u\n", hwcfg->lanes); |
3021 | |||
3022 | /* xshutdown GPIO is optional */ | ||
3023 | pdata->xshutdown = of_get_named_gpio(dev->of_node, "reset-gpios", 0); | ||
3024 | 3008 | ||
3025 | /* NVM size is not mandatory */ | 3009 | /* NVM size is not mandatory */ |
3026 | of_property_read_u32(dev->of_node, "nokia,nvm-size", | 3010 | of_property_read_u32(dev->of_node, "nokia,nvm-size", |
3027 | &pdata->nvm_size); | 3011 | &hwcfg->nvm_size); |
3028 | 3012 | ||
3029 | rval = of_property_read_u32(dev->of_node, "clock-frequency", | 3013 | rval = of_property_read_u32(dev->of_node, "clock-frequency", |
3030 | &pdata->ext_clk); | 3014 | &hwcfg->ext_clk); |
3031 | if (rval) { | 3015 | if (rval) { |
3032 | dev_warn(dev, "can't get clock-frequency\n"); | 3016 | dev_warn(dev, "can't get clock-frequency\n"); |
3033 | goto out_err; | 3017 | goto out_err; |
3034 | } | 3018 | } |
3035 | 3019 | ||
3036 | dev_dbg(dev, "reset %d, nvm %d, clk %d, csi %d\n", pdata->xshutdown, | 3020 | dev_dbg(dev, "nvm %d, clk %d, csi %d\n", hwcfg->nvm_size, |
3037 | pdata->nvm_size, pdata->ext_clk, pdata->csi_signalling_mode); | 3021 | hwcfg->ext_clk, hwcfg->csi_signalling_mode); |
3038 | 3022 | ||
3039 | if (!bus_cfg->nr_of_link_frequencies) { | 3023 | if (!bus_cfg->nr_of_link_frequencies) { |
3040 | dev_warn(dev, "no link frequencies defined\n"); | 3024 | dev_warn(dev, "no link frequencies defined\n"); |
3041 | goto out_err; | 3025 | goto out_err; |
3042 | } | 3026 | } |
3043 | 3027 | ||
3044 | pdata->op_sys_clock = devm_kcalloc( | 3028 | hwcfg->op_sys_clock = devm_kcalloc( |
3045 | dev, bus_cfg->nr_of_link_frequencies + 1 /* guardian */, | 3029 | dev, bus_cfg->nr_of_link_frequencies + 1 /* guardian */, |
3046 | sizeof(*pdata->op_sys_clock), GFP_KERNEL); | 3030 | sizeof(*hwcfg->op_sys_clock), GFP_KERNEL); |
3047 | if (!pdata->op_sys_clock) | 3031 | if (!hwcfg->op_sys_clock) |
3048 | goto out_err; | 3032 | goto out_err; |
3049 | 3033 | ||
3050 | for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) { | 3034 | for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) { |
3051 | pdata->op_sys_clock[i] = bus_cfg->link_frequencies[i]; | 3035 | hwcfg->op_sys_clock[i] = bus_cfg->link_frequencies[i]; |
3052 | dev_dbg(dev, "freq %d: %lld\n", i, pdata->op_sys_clock[i]); | 3036 | dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]); |
3053 | } | 3037 | } |
3054 | 3038 | ||
3055 | v4l2_of_free_endpoint(bus_cfg); | 3039 | v4l2_of_free_endpoint(bus_cfg); |
3056 | of_node_put(ep); | 3040 | of_node_put(ep); |
3057 | return pdata; | 3041 | return hwcfg; |
3058 | 3042 | ||
3059 | out_err: | 3043 | out_err: |
3060 | v4l2_of_free_endpoint(bus_cfg); | 3044 | v4l2_of_free_endpoint(bus_cfg); |
@@ -3066,17 +3050,17 @@ static int smiapp_probe(struct i2c_client *client, | |||
3066 | const struct i2c_device_id *devid) | 3050 | const struct i2c_device_id *devid) |
3067 | { | 3051 | { |
3068 | struct smiapp_sensor *sensor; | 3052 | struct smiapp_sensor *sensor; |
3069 | struct smiapp_platform_data *pdata = smiapp_get_pdata(&client->dev); | 3053 | struct smiapp_hwconfig *hwcfg = smiapp_get_hwconfig(&client->dev); |
3070 | int rval; | 3054 | int rval; |
3071 | 3055 | ||
3072 | if (pdata == NULL) | 3056 | if (hwcfg == NULL) |
3073 | return -ENODEV; | 3057 | return -ENODEV; |
3074 | 3058 | ||
3075 | sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); | 3059 | sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); |
3076 | if (sensor == NULL) | 3060 | if (sensor == NULL) |
3077 | return -ENOMEM; | 3061 | return -ENOMEM; |
3078 | 3062 | ||
3079 | sensor->platform_data = pdata; | 3063 | sensor->hwcfg = hwcfg; |
3080 | mutex_init(&sensor->mutex); | 3064 | mutex_init(&sensor->mutex); |
3081 | mutex_init(&sensor->power_mutex); | 3065 | mutex_init(&sensor->power_mutex); |
3082 | sensor->src = &sensor->ssds[sensor->ssds_used]; | 3066 | sensor->src = &sensor->ssds[sensor->ssds_used]; |
@@ -3119,12 +3103,8 @@ static int smiapp_remove(struct i2c_client *client) | |||
3119 | v4l2_async_unregister_subdev(subdev); | 3103 | v4l2_async_unregister_subdev(subdev); |
3120 | 3104 | ||
3121 | if (sensor->power_count) { | 3105 | if (sensor->power_count) { |
3122 | if (gpio_is_valid(sensor->platform_data->xshutdown)) | 3106 | gpiod_set_value(sensor->xshutdown, 0); |
3123 | gpio_set_value(sensor->platform_data->xshutdown, 0); | 3107 | clk_disable_unprepare(sensor->ext_clk); |
3124 | if (sensor->platform_data->set_xclk) | ||
3125 | sensor->platform_data->set_xclk(&sensor->src->sd, 0); | ||
3126 | else | ||
3127 | clk_disable_unprepare(sensor->ext_clk); | ||
3128 | sensor->power_count = 0; | 3108 | sensor->power_count = 0; |
3129 | } | 3109 | } |
3130 | 3110 | ||
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index abf9ea7a0fb7..cb128eae9c54 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c | |||
@@ -26,7 +26,7 @@ static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val) | |||
26 | } | 26 | } |
27 | 27 | ||
28 | static int smiapp_write_8s(struct smiapp_sensor *sensor, | 28 | static int smiapp_write_8s(struct smiapp_sensor *sensor, |
29 | struct smiapp_reg_8 *regs, int len) | 29 | const struct smiapp_reg_8 *regs, int len) |
30 | { | 30 | { |
31 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | 31 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); |
32 | int rval; | 32 | int rval; |
@@ -71,7 +71,7 @@ static int jt8ew9_limits(struct smiapp_sensor *sensor) | |||
71 | 71 | ||
72 | static int jt8ew9_post_poweron(struct smiapp_sensor *sensor) | 72 | static int jt8ew9_post_poweron(struct smiapp_sensor *sensor) |
73 | { | 73 | { |
74 | struct smiapp_reg_8 regs[] = { | 74 | const struct smiapp_reg_8 regs[] = { |
75 | { 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */ | 75 | { 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */ |
76 | { 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ | 76 | { 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ |
77 | { 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ | 77 | { 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ |
@@ -115,7 +115,7 @@ const struct smiapp_quirk smiapp_jt8ew9_quirk = { | |||
115 | static int imx125es_post_poweron(struct smiapp_sensor *sensor) | 115 | static int imx125es_post_poweron(struct smiapp_sensor *sensor) |
116 | { | 116 | { |
117 | /* Taken from v02. No idea what the other two are. */ | 117 | /* Taken from v02. No idea what the other two are. */ |
118 | struct smiapp_reg_8 regs[] = { | 118 | const struct smiapp_reg_8 regs[] = { |
119 | /* | 119 | /* |
120 | * 0x3302: clk during frame blanking: | 120 | * 0x3302: clk during frame blanking: |
121 | * 0x00 - HS mode, 0x01 - LP11 | 121 | * 0x00 - HS mode, 0x01 - LP11 |
@@ -145,8 +145,7 @@ static int jt8ev1_post_poweron(struct smiapp_sensor *sensor) | |||
145 | { | 145 | { |
146 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | 146 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); |
147 | int rval; | 147 | int rval; |
148 | 148 | const struct smiapp_reg_8 regs[] = { | |
149 | struct smiapp_reg_8 regs[] = { | ||
150 | { 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */ | 149 | { 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */ |
151 | { 0x30a3, 0xd0 }, /* FLASH STROBE enable */ | 150 | { 0x30a3, 0xd0 }, /* FLASH STROBE enable */ |
152 | { 0x3237, 0x00 }, /* For control of pulse timing for ADC */ | 151 | { 0x3237, 0x00 }, /* For control of pulse timing for ADC */ |
@@ -167,8 +166,7 @@ static int jt8ev1_post_poweron(struct smiapp_sensor *sensor) | |||
167 | { 0x33cf, 0xec }, /* For Black sun */ | 166 | { 0x33cf, 0xec }, /* For Black sun */ |
168 | { 0x3328, 0x80 }, /* Ugh. No idea what's this. */ | 167 | { 0x3328, 0x80 }, /* Ugh. No idea what's this. */ |
169 | }; | 168 | }; |
170 | 169 | const struct smiapp_reg_8 regs_96[] = { | |
171 | struct smiapp_reg_8 regs_96[] = { | ||
172 | { 0x30ae, 0x00 }, /* For control of ADC clock */ | 170 | { 0x30ae, 0x00 }, /* For control of ADC clock */ |
173 | { 0x30af, 0xd0 }, | 171 | { 0x30af, 0xd0 }, |
174 | { 0x30b0, 0x01 }, | 172 | { 0x30b0, 0x01 }, |
@@ -178,13 +176,13 @@ static int jt8ev1_post_poweron(struct smiapp_sensor *sensor) | |||
178 | if (rval < 0) | 176 | if (rval < 0) |
179 | return rval; | 177 | return rval; |
180 | 178 | ||
181 | switch (sensor->platform_data->ext_clk) { | 179 | switch (sensor->hwcfg->ext_clk) { |
182 | case 9600000: | 180 | case 9600000: |
183 | return smiapp_write_8s(sensor, regs_96, | 181 | return smiapp_write_8s(sensor, regs_96, |
184 | ARRAY_SIZE(regs_96)); | 182 | ARRAY_SIZE(regs_96)); |
185 | default: | 183 | default: |
186 | dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n", | 184 | dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n", |
187 | sensor->platform_data->ext_clk); | 185 | sensor->hwcfg->ext_clk); |
188 | return 0; | 186 | return 0; |
189 | } | 187 | } |
190 | } | 188 | } |
diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c index 6b6c20b61397..1e501c06d18c 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.c +++ b/drivers/media/i2c/smiapp/smiapp-regs.c | |||
@@ -188,7 +188,8 @@ int smiapp_read_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val) | |||
188 | SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY)); | 188 | SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY)); |
189 | } | 189 | } |
190 | 190 | ||
191 | int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val) | 191 | static int smiapp_read_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val, |
192 | bool force8) | ||
192 | { | 193 | { |
193 | int rval; | 194 | int rval; |
194 | 195 | ||
@@ -199,21 +200,20 @@ int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val) | |||
199 | if (rval < 0) | 200 | if (rval < 0) |
200 | return rval; | 201 | return rval; |
201 | 202 | ||
203 | if (force8) | ||
204 | return __smiapp_read(sensor, reg, val, true); | ||
205 | |||
202 | return smiapp_read_no_quirk(sensor, reg, val); | 206 | return smiapp_read_no_quirk(sensor, reg, val); |
203 | } | 207 | } |
204 | 208 | ||
205 | int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val) | 209 | int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val) |
206 | { | 210 | { |
207 | int rval; | 211 | return smiapp_read_quirk(sensor, reg, val, false); |
208 | 212 | } | |
209 | *val = 0; | ||
210 | rval = smiapp_call_quirk(sensor, reg_access, false, ®, val); | ||
211 | if (rval == -ENOIOCTLCMD) | ||
212 | return 0; | ||
213 | if (rval < 0) | ||
214 | return rval; | ||
215 | 213 | ||
216 | return __smiapp_read(sensor, reg, val, true); | 214 | int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val) |
215 | { | ||
216 | return smiapp_read_quirk(sensor, reg, val, true); | ||
217 | } | 217 | } |
218 | 218 | ||
219 | int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val) | 219 | int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val) |
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index 2174f89a00db..aae72bc87bf7 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h | |||
@@ -151,7 +151,7 @@ struct smiapp_csi_data_format { | |||
151 | #define SMIAPP_PADS 2 | 151 | #define SMIAPP_PADS 2 |
152 | 152 | ||
153 | #define SMIAPP_COMPRESSED_BASE 8 | 153 | #define SMIAPP_COMPRESSED_BASE 8 |
154 | #define SMIAPP_COMPRESSED_MAX 12 | 154 | #define SMIAPP_COMPRESSED_MAX 16 |
155 | #define SMIAPP_NR_OF_COMPRESSED (SMIAPP_COMPRESSED_MAX - \ | 155 | #define SMIAPP_NR_OF_COMPRESSED (SMIAPP_COMPRESSED_MAX - \ |
156 | SMIAPP_COMPRESSED_BASE + 1) | 156 | SMIAPP_COMPRESSED_BASE + 1) |
157 | 157 | ||
@@ -197,9 +197,10 @@ struct smiapp_sensor { | |||
197 | struct smiapp_subdev *binner; | 197 | struct smiapp_subdev *binner; |
198 | struct smiapp_subdev *scaler; | 198 | struct smiapp_subdev *scaler; |
199 | struct smiapp_subdev *pixel_array; | 199 | struct smiapp_subdev *pixel_array; |
200 | struct smiapp_platform_data *platform_data; | 200 | struct smiapp_hwconfig *hwcfg; |
201 | struct regulator *vana; | 201 | struct regulator *vana; |
202 | struct clk *ext_clk; | 202 | struct clk *ext_clk; |
203 | struct gpio_desc *xshutdown; | ||
203 | u32 limits[SMIAPP_LIMIT_LAST]; | 204 | u32 limits[SMIAPP_LIMIT_LAST]; |
204 | u8 nbinning_subtypes; | 205 | u8 nbinning_subtypes; |
205 | struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES]; | 206 | struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES]; |
diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index 23d352f0adf0..7704bcf5cc25 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig | |||
@@ -14,11 +14,14 @@ config SOC_CAMERA_MT9M001 | |||
14 | and colour models. | 14 | and colour models. |
15 | 15 | ||
16 | config SOC_CAMERA_MT9M111 | 16 | config SOC_CAMERA_MT9M111 |
17 | tristate "mt9m111, mt9m112 and mt9m131 support" | 17 | tristate "legacy soc_camera mt9m111, mt9m112 and mt9m131 support" |
18 | depends on SOC_CAMERA && I2C | 18 | depends on SOC_CAMERA && I2C |
19 | select VIDEO_MT9M111 | ||
19 | help | 20 | help |
20 | This driver supports MT9M111, MT9M112 and MT9M131 cameras from | 21 | This driver supports MT9M111, MT9M112 and MT9M131 cameras from |
21 | Micron/Aptina | 22 | Micron/Aptina. |
23 | This is the legacy configuration which shouldn't be used anymore, | ||
24 | while VIDEO_MT9M111 should be used instead. | ||
22 | 25 | ||
23 | config SOC_CAMERA_MT9T031 | 26 | config SOC_CAMERA_MT9T031 |
24 | tristate "mt9t031 support" | 27 | tristate "mt9t031 support" |
diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile index d0421feaa796..6f994f9353a0 100644 --- a/drivers/media/i2c/soc_camera/Makefile +++ b/drivers/media/i2c/soc_camera/Makefile | |||
@@ -1,6 +1,5 @@ | |||
1 | obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o | 1 | obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o |
2 | obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o | 2 | obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o |
3 | obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o | ||
4 | obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o | 3 | obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o |
5 | obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o | 4 | obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o |
6 | obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o | 5 | obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o |
diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c index f68c2352c63c..05b55cfe8147 100644 --- a/drivers/media/i2c/soc_camera/imx074.c +++ b/drivers/media/i2c/soc_camera/imx074.c | |||
@@ -209,31 +209,26 @@ static int imx074_get_fmt(struct v4l2_subdev *sd, | |||
209 | return 0; | 209 | return 0; |
210 | } | 210 | } |
211 | 211 | ||
212 | static int imx074_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 212 | static int imx074_get_selection(struct v4l2_subdev *sd, |
213 | struct v4l2_subdev_pad_config *cfg, | ||
214 | struct v4l2_subdev_selection *sel) | ||
213 | { | 215 | { |
214 | struct v4l2_rect *rect = &a->c; | 216 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
215 | 217 | return -EINVAL; | |
216 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
217 | rect->top = 0; | ||
218 | rect->left = 0; | ||
219 | rect->width = IMX074_WIDTH; | ||
220 | rect->height = IMX074_HEIGHT; | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | 218 | ||
225 | static int imx074_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | 219 | sel->r.left = 0; |
226 | { | 220 | sel->r.top = 0; |
227 | a->bounds.left = 0; | 221 | sel->r.width = IMX074_WIDTH; |
228 | a->bounds.top = 0; | 222 | sel->r.height = IMX074_HEIGHT; |
229 | a->bounds.width = IMX074_WIDTH; | ||
230 | a->bounds.height = IMX074_HEIGHT; | ||
231 | a->defrect = a->bounds; | ||
232 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
233 | a->pixelaspect.numerator = 1; | ||
234 | a->pixelaspect.denominator = 1; | ||
235 | 223 | ||
236 | return 0; | 224 | switch (sel->target) { |
225 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
226 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
227 | case V4L2_SEL_TGT_CROP: | ||
228 | return 0; | ||
229 | default: | ||
230 | return -EINVAL; | ||
231 | } | ||
237 | } | 232 | } |
238 | 233 | ||
239 | static int imx074_enum_mbus_code(struct v4l2_subdev *sd, | 234 | static int imx074_enum_mbus_code(struct v4l2_subdev *sd, |
@@ -278,8 +273,6 @@ static int imx074_g_mbus_config(struct v4l2_subdev *sd, | |||
278 | 273 | ||
279 | static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { | 274 | static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { |
280 | .s_stream = imx074_s_stream, | 275 | .s_stream = imx074_s_stream, |
281 | .g_crop = imx074_g_crop, | ||
282 | .cropcap = imx074_cropcap, | ||
283 | .g_mbus_config = imx074_g_mbus_config, | 276 | .g_mbus_config = imx074_g_mbus_config, |
284 | }; | 277 | }; |
285 | 278 | ||
@@ -289,6 +282,7 @@ static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { | |||
289 | 282 | ||
290 | static const struct v4l2_subdev_pad_ops imx074_subdev_pad_ops = { | 283 | static const struct v4l2_subdev_pad_ops imx074_subdev_pad_ops = { |
291 | .enum_mbus_code = imx074_enum_mbus_code, | 284 | .enum_mbus_code = imx074_enum_mbus_code, |
285 | .get_selection = imx074_get_selection, | ||
292 | .get_fmt = imx074_get_fmt, | 286 | .get_fmt = imx074_get_fmt, |
293 | .set_fmt = imx074_set_fmt, | 287 | .set_fmt = imx074_set_fmt, |
294 | }; | 288 | }; |
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index 69becc358659..3d6378d4491c 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c | |||
@@ -171,13 +171,19 @@ static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) | |||
171 | return 0; | 171 | return 0; |
172 | } | 172 | } |
173 | 173 | ||
174 | static int mt9m001_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | 174 | static int mt9m001_set_selection(struct v4l2_subdev *sd, |
175 | struct v4l2_subdev_pad_config *cfg, | ||
176 | struct v4l2_subdev_selection *sel) | ||
175 | { | 177 | { |
176 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 178 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
177 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 179 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
178 | struct v4l2_rect rect = a->c; | 180 | struct v4l2_rect rect = sel->r; |
179 | int ret; | ||
180 | const u16 hblank = 9, vblank = 25; | 181 | const u16 hblank = 9, vblank = 25; |
182 | int ret; | ||
183 | |||
184 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || | ||
185 | sel->target != V4L2_SEL_TGT_CROP) | ||
186 | return -EINVAL; | ||
181 | 187 | ||
182 | if (mt9m001->fmts == mt9m001_colour_fmts) | 188 | if (mt9m001->fmts == mt9m001_colour_fmts) |
183 | /* | 189 | /* |
@@ -225,29 +231,30 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | |||
225 | return ret; | 231 | return ret; |
226 | } | 232 | } |
227 | 233 | ||
228 | static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 234 | static int mt9m001_get_selection(struct v4l2_subdev *sd, |
235 | struct v4l2_subdev_pad_config *cfg, | ||
236 | struct v4l2_subdev_selection *sel) | ||
229 | { | 237 | { |
230 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 238 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
231 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 239 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
232 | 240 | ||
233 | a->c = mt9m001->rect; | 241 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
234 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 242 | return -EINVAL; |
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
240 | { | ||
241 | a->bounds.left = MT9M001_COLUMN_SKIP; | ||
242 | a->bounds.top = MT9M001_ROW_SKIP; | ||
243 | a->bounds.width = MT9M001_MAX_WIDTH; | ||
244 | a->bounds.height = MT9M001_MAX_HEIGHT; | ||
245 | a->defrect = a->bounds; | ||
246 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
247 | a->pixelaspect.numerator = 1; | ||
248 | a->pixelaspect.denominator = 1; | ||
249 | 243 | ||
250 | return 0; | 244 | switch (sel->target) { |
245 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
246 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
247 | sel->r.left = MT9M001_COLUMN_SKIP; | ||
248 | sel->r.top = MT9M001_ROW_SKIP; | ||
249 | sel->r.width = MT9M001_MAX_WIDTH; | ||
250 | sel->r.height = MT9M001_MAX_HEIGHT; | ||
251 | return 0; | ||
252 | case V4L2_SEL_TGT_CROP: | ||
253 | sel->r = mt9m001->rect; | ||
254 | return 0; | ||
255 | default: | ||
256 | return -EINVAL; | ||
257 | } | ||
251 | } | 258 | } |
252 | 259 | ||
253 | static int mt9m001_get_fmt(struct v4l2_subdev *sd, | 260 | static int mt9m001_get_fmt(struct v4l2_subdev *sd, |
@@ -275,18 +282,18 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd, | |||
275 | { | 282 | { |
276 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 283 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
277 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 284 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
278 | struct v4l2_crop a = { | 285 | struct v4l2_subdev_selection sel = { |
279 | .c = { | 286 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
280 | .left = mt9m001->rect.left, | 287 | .target = V4L2_SEL_TGT_CROP, |
281 | .top = mt9m001->rect.top, | 288 | .r.left = mt9m001->rect.left, |
282 | .width = mf->width, | 289 | .r.top = mt9m001->rect.top, |
283 | .height = mf->height, | 290 | .r.width = mf->width, |
284 | }, | 291 | .r.height = mf->height, |
285 | }; | 292 | }; |
286 | int ret; | 293 | int ret; |
287 | 294 | ||
288 | /* No support for scaling so far, just crop. TODO: use skipping */ | 295 | /* No support for scaling so far, just crop. TODO: use skipping */ |
289 | ret = mt9m001_s_crop(sd, &a); | 296 | ret = mt9m001_set_selection(sd, NULL, &sel); |
290 | if (!ret) { | 297 | if (!ret) { |
291 | mf->width = mt9m001->rect.width; | 298 | mf->width = mt9m001->rect.width; |
292 | mf->height = mt9m001->rect.height; | 299 | mf->height = mt9m001->rect.height; |
@@ -625,9 +632,6 @@ static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, | |||
625 | 632 | ||
626 | static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { | 633 | static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { |
627 | .s_stream = mt9m001_s_stream, | 634 | .s_stream = mt9m001_s_stream, |
628 | .s_crop = mt9m001_s_crop, | ||
629 | .g_crop = mt9m001_g_crop, | ||
630 | .cropcap = mt9m001_cropcap, | ||
631 | .g_mbus_config = mt9m001_g_mbus_config, | 635 | .g_mbus_config = mt9m001_g_mbus_config, |
632 | .s_mbus_config = mt9m001_s_mbus_config, | 636 | .s_mbus_config = mt9m001_s_mbus_config, |
633 | }; | 637 | }; |
@@ -638,6 +642,8 @@ static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { | |||
638 | 642 | ||
639 | static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = { | 643 | static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = { |
640 | .enum_mbus_code = mt9m001_enum_mbus_code, | 644 | .enum_mbus_code = mt9m001_enum_mbus_code, |
645 | .get_selection = mt9m001_get_selection, | ||
646 | .set_selection = mt9m001_set_selection, | ||
641 | .get_fmt = mt9m001_get_fmt, | 647 | .get_fmt = mt9m001_get_fmt, |
642 | .set_fmt = mt9m001_set_fmt, | 648 | .set_fmt = mt9m001_set_fmt, |
643 | }; | 649 | }; |
diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index 5c8e3ffe3b27..3aa5569065ad 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c | |||
@@ -264,7 +264,7 @@ static int mt9t031_set_params(struct i2c_client *client, | |||
264 | 264 | ||
265 | /* | 265 | /* |
266 | * The caller provides a supported format, as guaranteed by | 266 | * The caller provides a supported format, as guaranteed by |
267 | * .set_fmt(FORMAT_TRY), soc_camera_s_crop() and soc_camera_cropcap() | 267 | * .set_fmt(FORMAT_TRY), soc_camera_s_selection() and soc_camera_cropcap() |
268 | */ | 268 | */ |
269 | if (ret >= 0) | 269 | if (ret >= 0) |
270 | ret = reg_write(client, MT9T031_COLUMN_START, rect->left); | 270 | ret = reg_write(client, MT9T031_COLUMN_START, rect->left); |
@@ -294,11 +294,17 @@ static int mt9t031_set_params(struct i2c_client *client, | |||
294 | return ret < 0 ? ret : 0; | 294 | return ret < 0 ? ret : 0; |
295 | } | 295 | } |
296 | 296 | ||
297 | static int mt9t031_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | 297 | static int mt9t031_set_selection(struct v4l2_subdev *sd, |
298 | struct v4l2_subdev_pad_config *cfg, | ||
299 | struct v4l2_subdev_selection *sel) | ||
298 | { | 300 | { |
299 | struct v4l2_rect rect = a->c; | ||
300 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 301 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
301 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 302 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
303 | struct v4l2_rect rect = sel->r; | ||
304 | |||
305 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || | ||
306 | sel->target != V4L2_SEL_TGT_CROP) | ||
307 | return -EINVAL; | ||
302 | 308 | ||
303 | rect.width = ALIGN(rect.width, 2); | 309 | rect.width = ALIGN(rect.width, 2); |
304 | rect.height = ALIGN(rect.height, 2); | 310 | rect.height = ALIGN(rect.height, 2); |
@@ -312,29 +318,30 @@ static int mt9t031_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | |||
312 | return mt9t031_set_params(client, &rect, mt9t031->xskip, mt9t031->yskip); | 318 | return mt9t031_set_params(client, &rect, mt9t031->xskip, mt9t031->yskip); |
313 | } | 319 | } |
314 | 320 | ||
315 | static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 321 | static int mt9t031_get_selection(struct v4l2_subdev *sd, |
322 | struct v4l2_subdev_pad_config *cfg, | ||
323 | struct v4l2_subdev_selection *sel) | ||
316 | { | 324 | { |
317 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 325 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
318 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 326 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
319 | 327 | ||
320 | a->c = mt9t031->rect; | 328 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
321 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 329 | return -EINVAL; |
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
327 | { | ||
328 | a->bounds.left = MT9T031_COLUMN_SKIP; | ||
329 | a->bounds.top = MT9T031_ROW_SKIP; | ||
330 | a->bounds.width = MT9T031_MAX_WIDTH; | ||
331 | a->bounds.height = MT9T031_MAX_HEIGHT; | ||
332 | a->defrect = a->bounds; | ||
333 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
334 | a->pixelaspect.numerator = 1; | ||
335 | a->pixelaspect.denominator = 1; | ||
336 | 330 | ||
337 | return 0; | 331 | switch (sel->target) { |
332 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
333 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
334 | sel->r.left = MT9T031_COLUMN_SKIP; | ||
335 | sel->r.top = MT9T031_ROW_SKIP; | ||
336 | sel->r.width = MT9T031_MAX_WIDTH; | ||
337 | sel->r.height = MT9T031_MAX_HEIGHT; | ||
338 | return 0; | ||
339 | case V4L2_SEL_TGT_CROP: | ||
340 | sel->r = mt9t031->rect; | ||
341 | return 0; | ||
342 | default: | ||
343 | return -EINVAL; | ||
344 | } | ||
338 | } | 345 | } |
339 | 346 | ||
340 | static int mt9t031_get_fmt(struct v4l2_subdev *sd, | 347 | static int mt9t031_get_fmt(struct v4l2_subdev *sd, |
@@ -721,9 +728,6 @@ static int mt9t031_s_mbus_config(struct v4l2_subdev *sd, | |||
721 | 728 | ||
722 | static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { | 729 | static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { |
723 | .s_stream = mt9t031_s_stream, | 730 | .s_stream = mt9t031_s_stream, |
724 | .s_crop = mt9t031_s_crop, | ||
725 | .g_crop = mt9t031_g_crop, | ||
726 | .cropcap = mt9t031_cropcap, | ||
727 | .g_mbus_config = mt9t031_g_mbus_config, | 731 | .g_mbus_config = mt9t031_g_mbus_config, |
728 | .s_mbus_config = mt9t031_s_mbus_config, | 732 | .s_mbus_config = mt9t031_s_mbus_config, |
729 | }; | 733 | }; |
@@ -734,6 +738,8 @@ static const struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { | |||
734 | 738 | ||
735 | static const struct v4l2_subdev_pad_ops mt9t031_subdev_pad_ops = { | 739 | static const struct v4l2_subdev_pad_ops mt9t031_subdev_pad_ops = { |
736 | .enum_mbus_code = mt9t031_enum_mbus_code, | 740 | .enum_mbus_code = mt9t031_enum_mbus_code, |
741 | .get_selection = mt9t031_get_selection, | ||
742 | .set_selection = mt9t031_set_selection, | ||
737 | .get_fmt = mt9t031_get_fmt, | 743 | .get_fmt = mt9t031_get_fmt, |
738 | .set_fmt = mt9t031_set_fmt, | 744 | .set_fmt = mt9t031_set_fmt, |
739 | }; | 745 | }; |
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 6a1b2a9f9a09..2ef22241ec14 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c | |||
@@ -867,39 +867,48 @@ static int mt9t112_set_params(struct mt9t112_priv *priv, | |||
867 | return 0; | 867 | return 0; |
868 | } | 868 | } |
869 | 869 | ||
870 | static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | 870 | static int mt9t112_get_selection(struct v4l2_subdev *sd, |
871 | { | 871 | struct v4l2_subdev_pad_config *cfg, |
872 | a->bounds.left = 0; | 872 | struct v4l2_subdev_selection *sel) |
873 | a->bounds.top = 0; | ||
874 | a->bounds.width = MAX_WIDTH; | ||
875 | a->bounds.height = MAX_HEIGHT; | ||
876 | a->defrect.left = 0; | ||
877 | a->defrect.top = 0; | ||
878 | a->defrect.width = VGA_WIDTH; | ||
879 | a->defrect.height = VGA_HEIGHT; | ||
880 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
881 | a->pixelaspect.numerator = 1; | ||
882 | a->pixelaspect.denominator = 1; | ||
883 | |||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
888 | { | 873 | { |
889 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 874 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
890 | struct mt9t112_priv *priv = to_mt9t112(client); | 875 | struct mt9t112_priv *priv = to_mt9t112(client); |
891 | 876 | ||
892 | a->c = priv->frame; | 877 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
893 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 878 | return -EINVAL; |
894 | 879 | ||
895 | return 0; | 880 | switch (sel->target) { |
881 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
882 | sel->r.left = 0; | ||
883 | sel->r.top = 0; | ||
884 | sel->r.width = MAX_WIDTH; | ||
885 | sel->r.height = MAX_HEIGHT; | ||
886 | return 0; | ||
887 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
888 | sel->r.left = 0; | ||
889 | sel->r.top = 0; | ||
890 | sel->r.width = VGA_WIDTH; | ||
891 | sel->r.height = VGA_HEIGHT; | ||
892 | return 0; | ||
893 | case V4L2_SEL_TGT_CROP: | ||
894 | sel->r = priv->frame; | ||
895 | return 0; | ||
896 | default: | ||
897 | return -EINVAL; | ||
898 | } | ||
896 | } | 899 | } |
897 | 900 | ||
898 | static int mt9t112_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | 901 | static int mt9t112_set_selection(struct v4l2_subdev *sd, |
902 | struct v4l2_subdev_pad_config *cfg, | ||
903 | struct v4l2_subdev_selection *sel) | ||
899 | { | 904 | { |
900 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 905 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
901 | struct mt9t112_priv *priv = to_mt9t112(client); | 906 | struct mt9t112_priv *priv = to_mt9t112(client); |
902 | const struct v4l2_rect *rect = &a->c; | 907 | const struct v4l2_rect *rect = &sel->r; |
908 | |||
909 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || | ||
910 | sel->target != V4L2_SEL_TGT_CROP) | ||
911 | return -EINVAL; | ||
903 | 912 | ||
904 | return mt9t112_set_params(priv, rect, priv->format->code); | 913 | return mt9t112_set_params(priv, rect, priv->format->code); |
905 | } | 914 | } |
@@ -1024,15 +1033,14 @@ static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, | |||
1024 | 1033 | ||
1025 | static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { | 1034 | static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { |
1026 | .s_stream = mt9t112_s_stream, | 1035 | .s_stream = mt9t112_s_stream, |
1027 | .cropcap = mt9t112_cropcap, | ||
1028 | .g_crop = mt9t112_g_crop, | ||
1029 | .s_crop = mt9t112_s_crop, | ||
1030 | .g_mbus_config = mt9t112_g_mbus_config, | 1036 | .g_mbus_config = mt9t112_g_mbus_config, |
1031 | .s_mbus_config = mt9t112_s_mbus_config, | 1037 | .s_mbus_config = mt9t112_s_mbus_config, |
1032 | }; | 1038 | }; |
1033 | 1039 | ||
1034 | static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { | 1040 | static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { |
1035 | .enum_mbus_code = mt9t112_enum_mbus_code, | 1041 | .enum_mbus_code = mt9t112_enum_mbus_code, |
1042 | .get_selection = mt9t112_get_selection, | ||
1043 | .set_selection = mt9t112_set_selection, | ||
1036 | .get_fmt = mt9t112_get_fmt, | 1044 | .get_fmt = mt9t112_get_fmt, |
1037 | .set_fmt = mt9t112_set_fmt, | 1045 | .set_fmt = mt9t112_set_fmt, |
1038 | }; | 1046 | }; |
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 2721e583bfa0..6a14ab5e4f2d 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c | |||
@@ -276,14 +276,20 @@ static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) | |||
276 | return 0; | 276 | return 0; |
277 | } | 277 | } |
278 | 278 | ||
279 | static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | 279 | static int mt9v022_set_selection(struct v4l2_subdev *sd, |
280 | struct v4l2_subdev_pad_config *cfg, | ||
281 | struct v4l2_subdev_selection *sel) | ||
280 | { | 282 | { |
281 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 283 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
282 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 284 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
283 | struct v4l2_rect rect = a->c; | 285 | struct v4l2_rect rect = sel->r; |
284 | int min_row, min_blank; | 286 | int min_row, min_blank; |
285 | int ret; | 287 | int ret; |
286 | 288 | ||
289 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || | ||
290 | sel->target != V4L2_SEL_TGT_CROP) | ||
291 | return -EINVAL; | ||
292 | |||
287 | /* Bayer format - even size lengths */ | 293 | /* Bayer format - even size lengths */ |
288 | if (mt9v022->fmts == mt9v022_colour_fmts) { | 294 | if (mt9v022->fmts == mt9v022_colour_fmts) { |
289 | rect.width = ALIGN(rect.width, 2); | 295 | rect.width = ALIGN(rect.width, 2); |
@@ -350,29 +356,30 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | |||
350 | return 0; | 356 | return 0; |
351 | } | 357 | } |
352 | 358 | ||
353 | static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 359 | static int mt9v022_get_selection(struct v4l2_subdev *sd, |
360 | struct v4l2_subdev_pad_config *cfg, | ||
361 | struct v4l2_subdev_selection *sel) | ||
354 | { | 362 | { |
355 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 363 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
356 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 364 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
357 | 365 | ||
358 | a->c = mt9v022->rect; | 366 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
359 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 367 | return -EINVAL; |
360 | |||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
365 | { | ||
366 | a->bounds.left = MT9V022_COLUMN_SKIP; | ||
367 | a->bounds.top = MT9V022_ROW_SKIP; | ||
368 | a->bounds.width = MT9V022_MAX_WIDTH; | ||
369 | a->bounds.height = MT9V022_MAX_HEIGHT; | ||
370 | a->defrect = a->bounds; | ||
371 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
372 | a->pixelaspect.numerator = 1; | ||
373 | a->pixelaspect.denominator = 1; | ||
374 | 368 | ||
375 | return 0; | 369 | switch (sel->target) { |
370 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
371 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
372 | sel->r.left = MT9V022_COLUMN_SKIP; | ||
373 | sel->r.top = MT9V022_ROW_SKIP; | ||
374 | sel->r.width = MT9V022_MAX_WIDTH; | ||
375 | sel->r.height = MT9V022_MAX_HEIGHT; | ||
376 | return 0; | ||
377 | case V4L2_SEL_TGT_CROP: | ||
378 | sel->r = mt9v022->rect; | ||
379 | return 0; | ||
380 | default: | ||
381 | return -EINVAL; | ||
382 | } | ||
376 | } | 383 | } |
377 | 384 | ||
378 | static int mt9v022_get_fmt(struct v4l2_subdev *sd, | 385 | static int mt9v022_get_fmt(struct v4l2_subdev *sd, |
@@ -400,13 +407,13 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, | |||
400 | { | 407 | { |
401 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 408 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
402 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 409 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
403 | struct v4l2_crop a = { | 410 | struct v4l2_subdev_selection sel = { |
404 | .c = { | 411 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
405 | .left = mt9v022->rect.left, | 412 | .target = V4L2_SEL_TGT_CROP, |
406 | .top = mt9v022->rect.top, | 413 | .r.left = mt9v022->rect.left, |
407 | .width = mf->width, | 414 | .r.top = mt9v022->rect.top, |
408 | .height = mf->height, | 415 | .r.width = mf->width, |
409 | }, | 416 | .r.height = mf->height, |
410 | }; | 417 | }; |
411 | int ret; | 418 | int ret; |
412 | 419 | ||
@@ -430,7 +437,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, | |||
430 | } | 437 | } |
431 | 438 | ||
432 | /* No support for scaling on this camera, just crop. */ | 439 | /* No support for scaling on this camera, just crop. */ |
433 | ret = mt9v022_s_crop(sd, &a); | 440 | ret = mt9v022_set_selection(sd, NULL, &sel); |
434 | if (!ret) { | 441 | if (!ret) { |
435 | mf->width = mt9v022->rect.width; | 442 | mf->width = mt9v022->rect.width; |
436 | mf->height = mt9v022->rect.height; | 443 | mf->height = mt9v022->rect.height; |
@@ -853,9 +860,6 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, | |||
853 | 860 | ||
854 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { | 861 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { |
855 | .s_stream = mt9v022_s_stream, | 862 | .s_stream = mt9v022_s_stream, |
856 | .s_crop = mt9v022_s_crop, | ||
857 | .g_crop = mt9v022_g_crop, | ||
858 | .cropcap = mt9v022_cropcap, | ||
859 | .g_mbus_config = mt9v022_g_mbus_config, | 863 | .g_mbus_config = mt9v022_g_mbus_config, |
860 | .s_mbus_config = mt9v022_s_mbus_config, | 864 | .s_mbus_config = mt9v022_s_mbus_config, |
861 | }; | 865 | }; |
@@ -866,6 +870,8 @@ static const struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { | |||
866 | 870 | ||
867 | static const struct v4l2_subdev_pad_ops mt9v022_subdev_pad_ops = { | 871 | static const struct v4l2_subdev_pad_ops mt9v022_subdev_pad_ops = { |
868 | .enum_mbus_code = mt9v022_enum_mbus_code, | 872 | .enum_mbus_code = mt9v022_enum_mbus_code, |
873 | .get_selection = mt9v022_get_selection, | ||
874 | .set_selection = mt9v022_set_selection, | ||
869 | .get_fmt = mt9v022_get_fmt, | 875 | .get_fmt = mt9v022_get_fmt, |
870 | .set_fmt = mt9v022_set_fmt, | 876 | .set_fmt = mt9v022_set_fmt, |
871 | }; | 877 | }; |
diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 9b4f5deec748..56de18263359 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c | |||
@@ -928,29 +928,25 @@ static int ov2640_enum_mbus_code(struct v4l2_subdev *sd, | |||
928 | return 0; | 928 | return 0; |
929 | } | 929 | } |
930 | 930 | ||
931 | static int ov2640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 931 | static int ov2640_get_selection(struct v4l2_subdev *sd, |
932 | { | 932 | struct v4l2_subdev_pad_config *cfg, |
933 | a->c.left = 0; | 933 | struct v4l2_subdev_selection *sel) |
934 | a->c.top = 0; | ||
935 | a->c.width = UXGA_WIDTH; | ||
936 | a->c.height = UXGA_HEIGHT; | ||
937 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
938 | |||
939 | return 0; | ||
940 | } | ||
941 | |||
942 | static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
943 | { | 934 | { |
944 | a->bounds.left = 0; | 935 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
945 | a->bounds.top = 0; | 936 | return -EINVAL; |
946 | a->bounds.width = UXGA_WIDTH; | ||
947 | a->bounds.height = UXGA_HEIGHT; | ||
948 | a->defrect = a->bounds; | ||
949 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
950 | a->pixelaspect.numerator = 1; | ||
951 | a->pixelaspect.denominator = 1; | ||
952 | 937 | ||
953 | return 0; | 938 | switch (sel->target) { |
939 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
940 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
941 | case V4L2_SEL_TGT_CROP: | ||
942 | sel->r.left = 0; | ||
943 | sel->r.top = 0; | ||
944 | sel->r.width = UXGA_WIDTH; | ||
945 | sel->r.height = UXGA_HEIGHT; | ||
946 | return 0; | ||
947 | default: | ||
948 | return -EINVAL; | ||
949 | } | ||
954 | } | 950 | } |
955 | 951 | ||
956 | static int ov2640_video_probe(struct i2c_client *client) | 952 | static int ov2640_video_probe(struct i2c_client *client) |
@@ -1024,13 +1020,12 @@ static int ov2640_g_mbus_config(struct v4l2_subdev *sd, | |||
1024 | 1020 | ||
1025 | static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { | 1021 | static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { |
1026 | .s_stream = ov2640_s_stream, | 1022 | .s_stream = ov2640_s_stream, |
1027 | .cropcap = ov2640_cropcap, | ||
1028 | .g_crop = ov2640_g_crop, | ||
1029 | .g_mbus_config = ov2640_g_mbus_config, | 1023 | .g_mbus_config = ov2640_g_mbus_config, |
1030 | }; | 1024 | }; |
1031 | 1025 | ||
1032 | static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { | 1026 | static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { |
1033 | .enum_mbus_code = ov2640_enum_mbus_code, | 1027 | .enum_mbus_code = ov2640_enum_mbus_code, |
1028 | .get_selection = ov2640_get_selection, | ||
1034 | .get_fmt = ov2640_get_fmt, | 1029 | .get_fmt = ov2640_get_fmt, |
1035 | .set_fmt = ov2640_set_fmt, | 1030 | .set_fmt = ov2640_set_fmt, |
1036 | }; | 1031 | }; |
diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c index bab9ac0c1764..3d185bd622a3 100644 --- a/drivers/media/i2c/soc_camera/ov5642.c +++ b/drivers/media/i2c/soc_camera/ov5642.c | |||
@@ -850,13 +850,19 @@ static int ov5642_enum_mbus_code(struct v4l2_subdev *sd, | |||
850 | return 0; | 850 | return 0; |
851 | } | 851 | } |
852 | 852 | ||
853 | static int ov5642_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | 853 | static int ov5642_set_selection(struct v4l2_subdev *sd, |
854 | struct v4l2_subdev_pad_config *cfg, | ||
855 | struct v4l2_subdev_selection *sel) | ||
854 | { | 856 | { |
855 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 857 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
856 | struct ov5642 *priv = to_ov5642(client); | 858 | struct ov5642 *priv = to_ov5642(client); |
857 | struct v4l2_rect rect = a->c; | 859 | struct v4l2_rect rect = sel->r; |
858 | int ret; | 860 | int ret; |
859 | 861 | ||
862 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || | ||
863 | sel->target != V4L2_SEL_TGT_CROP) | ||
864 | return -EINVAL; | ||
865 | |||
860 | v4l_bound_align_image(&rect.width, 48, OV5642_MAX_WIDTH, 1, | 866 | v4l_bound_align_image(&rect.width, 48, OV5642_MAX_WIDTH, 1, |
861 | &rect.height, 32, OV5642_MAX_HEIGHT, 1, 0); | 867 | &rect.height, 32, OV5642_MAX_HEIGHT, 1, 0); |
862 | 868 | ||
@@ -878,32 +884,30 @@ static int ov5642_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | |||
878 | return ret; | 884 | return ret; |
879 | } | 885 | } |
880 | 886 | ||
881 | static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 887 | static int ov5642_get_selection(struct v4l2_subdev *sd, |
888 | struct v4l2_subdev_pad_config *cfg, | ||
889 | struct v4l2_subdev_selection *sel) | ||
882 | { | 890 | { |
883 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 891 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
884 | struct ov5642 *priv = to_ov5642(client); | 892 | struct ov5642 *priv = to_ov5642(client); |
885 | struct v4l2_rect *rect = &a->c; | ||
886 | 893 | ||
887 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 894 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
888 | return -EINVAL; | 895 | return -EINVAL; |
889 | 896 | ||
890 | *rect = priv->crop_rect; | 897 | switch (sel->target) { |
891 | 898 | case V4L2_SEL_TGT_CROP_BOUNDS: | |
892 | return 0; | 899 | case V4L2_SEL_TGT_CROP_DEFAULT: |
893 | } | 900 | sel->r.left = 0; |
894 | 901 | sel->r.top = 0; | |
895 | static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | 902 | sel->r.width = OV5642_MAX_WIDTH; |
896 | { | 903 | sel->r.height = OV5642_MAX_HEIGHT; |
897 | a->bounds.left = 0; | 904 | return 0; |
898 | a->bounds.top = 0; | 905 | case V4L2_SEL_TGT_CROP: |
899 | a->bounds.width = OV5642_MAX_WIDTH; | 906 | sel->r = priv->crop_rect; |
900 | a->bounds.height = OV5642_MAX_HEIGHT; | 907 | return 0; |
901 | a->defrect = a->bounds; | 908 | default: |
902 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 909 | return -EINVAL; |
903 | a->pixelaspect.numerator = 1; | 910 | } |
904 | a->pixelaspect.denominator = 1; | ||
905 | |||
906 | return 0; | ||
907 | } | 911 | } |
908 | 912 | ||
909 | static int ov5642_g_mbus_config(struct v4l2_subdev *sd, | 913 | static int ov5642_g_mbus_config(struct v4l2_subdev *sd, |
@@ -940,14 +944,13 @@ static int ov5642_s_power(struct v4l2_subdev *sd, int on) | |||
940 | } | 944 | } |
941 | 945 | ||
942 | static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { | 946 | static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { |
943 | .s_crop = ov5642_s_crop, | ||
944 | .g_crop = ov5642_g_crop, | ||
945 | .cropcap = ov5642_cropcap, | ||
946 | .g_mbus_config = ov5642_g_mbus_config, | 947 | .g_mbus_config = ov5642_g_mbus_config, |
947 | }; | 948 | }; |
948 | 949 | ||
949 | static const struct v4l2_subdev_pad_ops ov5642_subdev_pad_ops = { | 950 | static const struct v4l2_subdev_pad_ops ov5642_subdev_pad_ops = { |
950 | .enum_mbus_code = ov5642_enum_mbus_code, | 951 | .enum_mbus_code = ov5642_enum_mbus_code, |
952 | .get_selection = ov5642_get_selection, | ||
953 | .set_selection = ov5642_set_selection, | ||
951 | .get_fmt = ov5642_get_fmt, | 954 | .get_fmt = ov5642_get_fmt, |
952 | .set_fmt = ov5642_set_fmt, | 955 | .set_fmt = ov5642_set_fmt, |
953 | }; | 956 | }; |
diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index 1f8af1ee8352..4bf2995e1cb8 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c | |||
@@ -432,25 +432,43 @@ static int ov6650_s_power(struct v4l2_subdev *sd, int on) | |||
432 | return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); | 432 | return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); |
433 | } | 433 | } |
434 | 434 | ||
435 | static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 435 | static int ov6650_get_selection(struct v4l2_subdev *sd, |
436 | struct v4l2_subdev_pad_config *cfg, | ||
437 | struct v4l2_subdev_selection *sel) | ||
436 | { | 438 | { |
437 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 439 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
438 | struct ov6650 *priv = to_ov6650(client); | 440 | struct ov6650 *priv = to_ov6650(client); |
439 | 441 | ||
440 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 442 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
441 | a->c = priv->rect; | 443 | return -EINVAL; |
442 | 444 | ||
443 | return 0; | 445 | switch (sel->target) { |
446 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
447 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
448 | sel->r.left = DEF_HSTRT << 1; | ||
449 | sel->r.top = DEF_VSTRT << 1; | ||
450 | sel->r.width = W_CIF; | ||
451 | sel->r.height = H_CIF; | ||
452 | return 0; | ||
453 | case V4L2_SEL_TGT_CROP: | ||
454 | sel->r = priv->rect; | ||
455 | return 0; | ||
456 | default: | ||
457 | return -EINVAL; | ||
458 | } | ||
444 | } | 459 | } |
445 | 460 | ||
446 | static int ov6650_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | 461 | static int ov6650_set_selection(struct v4l2_subdev *sd, |
462 | struct v4l2_subdev_pad_config *cfg, | ||
463 | struct v4l2_subdev_selection *sel) | ||
447 | { | 464 | { |
448 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 465 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
449 | struct ov6650 *priv = to_ov6650(client); | 466 | struct ov6650 *priv = to_ov6650(client); |
450 | struct v4l2_rect rect = a->c; | 467 | struct v4l2_rect rect = sel->r; |
451 | int ret; | 468 | int ret; |
452 | 469 | ||
453 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 470 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || |
471 | sel->target != V4L2_SEL_TGT_CROP) | ||
454 | return -EINVAL; | 472 | return -EINVAL; |
455 | 473 | ||
456 | rect.left = ALIGN(rect.left, 2); | 474 | rect.left = ALIGN(rect.left, 2); |
@@ -483,22 +501,6 @@ static int ov6650_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | |||
483 | return ret; | 501 | return ret; |
484 | } | 502 | } |
485 | 503 | ||
486 | static int ov6650_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
487 | { | ||
488 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
489 | return -EINVAL; | ||
490 | |||
491 | a->bounds.left = DEF_HSTRT << 1; | ||
492 | a->bounds.top = DEF_VSTRT << 1; | ||
493 | a->bounds.width = W_CIF; | ||
494 | a->bounds.height = H_CIF; | ||
495 | a->defrect = a->bounds; | ||
496 | a->pixelaspect.numerator = 1; | ||
497 | a->pixelaspect.denominator = 1; | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int ov6650_get_fmt(struct v4l2_subdev *sd, | 504 | static int ov6650_get_fmt(struct v4l2_subdev *sd, |
503 | struct v4l2_subdev_pad_config *cfg, | 505 | struct v4l2_subdev_pad_config *cfg, |
504 | struct v4l2_subdev_format *format) | 506 | struct v4l2_subdev_format *format) |
@@ -549,16 +551,15 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) | |||
549 | struct soc_camera_sense *sense = icd->sense; | 551 | struct soc_camera_sense *sense = icd->sense; |
550 | struct ov6650 *priv = to_ov6650(client); | 552 | struct ov6650 *priv = to_ov6650(client); |
551 | bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); | 553 | bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); |
552 | struct v4l2_crop a = { | 554 | struct v4l2_subdev_selection sel = { |
553 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | 555 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
554 | .c = { | 556 | .target = V4L2_SEL_TGT_CROP, |
555 | .left = priv->rect.left + (priv->rect.width >> 1) - | 557 | .r.left = priv->rect.left + (priv->rect.width >> 1) - |
556 | (mf->width >> (1 - half_scale)), | 558 | (mf->width >> (1 - half_scale)), |
557 | .top = priv->rect.top + (priv->rect.height >> 1) - | 559 | .r.top = priv->rect.top + (priv->rect.height >> 1) - |
558 | (mf->height >> (1 - half_scale)), | 560 | (mf->height >> (1 - half_scale)), |
559 | .width = mf->width << half_scale, | 561 | .r.width = mf->width << half_scale, |
560 | .height = mf->height << half_scale, | 562 | .r.height = mf->height << half_scale, |
561 | }, | ||
562 | }; | 563 | }; |
563 | u32 code = mf->code; | 564 | u32 code = mf->code; |
564 | unsigned long mclk, pclk; | 565 | unsigned long mclk, pclk; |
@@ -672,7 +673,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) | |||
672 | dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n", | 673 | dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n", |
673 | mclk / pclk, 10 * mclk % pclk / pclk); | 674 | mclk / pclk, 10 * mclk % pclk / pclk); |
674 | 675 | ||
675 | ret = ov6650_s_crop(sd, &a); | 676 | ret = ov6650_set_selection(sd, NULL, &sel); |
676 | if (!ret) | 677 | if (!ret) |
677 | ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask); | 678 | ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask); |
678 | if (!ret) | 679 | if (!ret) |
@@ -943,9 +944,6 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd, | |||
943 | 944 | ||
944 | static struct v4l2_subdev_video_ops ov6650_video_ops = { | 945 | static struct v4l2_subdev_video_ops ov6650_video_ops = { |
945 | .s_stream = ov6650_s_stream, | 946 | .s_stream = ov6650_s_stream, |
946 | .cropcap = ov6650_cropcap, | ||
947 | .g_crop = ov6650_g_crop, | ||
948 | .s_crop = ov6650_s_crop, | ||
949 | .g_parm = ov6650_g_parm, | 947 | .g_parm = ov6650_g_parm, |
950 | .s_parm = ov6650_s_parm, | 948 | .s_parm = ov6650_s_parm, |
951 | .g_mbus_config = ov6650_g_mbus_config, | 949 | .g_mbus_config = ov6650_g_mbus_config, |
@@ -954,6 +952,8 @@ static struct v4l2_subdev_video_ops ov6650_video_ops = { | |||
954 | 952 | ||
955 | static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { | 953 | static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { |
956 | .enum_mbus_code = ov6650_enum_mbus_code, | 954 | .enum_mbus_code = ov6650_enum_mbus_code, |
955 | .get_selection = ov6650_get_selection, | ||
956 | .set_selection = ov6650_set_selection, | ||
957 | .get_fmt = ov6650_get_fmt, | 957 | .get_fmt = ov6650_get_fmt, |
958 | .set_fmt = ov6650_set_fmt, | 958 | .set_fmt = ov6650_set_fmt, |
959 | }; | 959 | }; |
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index a43410c1e254..7e68762b3a4b 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c | |||
@@ -851,29 +851,28 @@ ov772x_set_fmt_error: | |||
851 | return ret; | 851 | return ret; |
852 | } | 852 | } |
853 | 853 | ||
854 | static int ov772x_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 854 | static int ov772x_get_selection(struct v4l2_subdev *sd, |
855 | { | 855 | struct v4l2_subdev_pad_config *cfg, |
856 | a->c.left = 0; | 856 | struct v4l2_subdev_selection *sel) |
857 | a->c.top = 0; | ||
858 | a->c.width = VGA_WIDTH; | ||
859 | a->c.height = VGA_HEIGHT; | ||
860 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
861 | |||
862 | return 0; | ||
863 | } | ||
864 | |||
865 | static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
866 | { | 857 | { |
867 | a->bounds.left = 0; | 858 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
868 | a->bounds.top = 0; | 859 | return -EINVAL; |
869 | a->bounds.width = OV772X_MAX_WIDTH; | ||
870 | a->bounds.height = OV772X_MAX_HEIGHT; | ||
871 | a->defrect = a->bounds; | ||
872 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
873 | a->pixelaspect.numerator = 1; | ||
874 | a->pixelaspect.denominator = 1; | ||
875 | 860 | ||
876 | return 0; | 861 | sel->r.left = 0; |
862 | sel->r.top = 0; | ||
863 | switch (sel->target) { | ||
864 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
865 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
866 | sel->r.width = OV772X_MAX_WIDTH; | ||
867 | sel->r.height = OV772X_MAX_HEIGHT; | ||
868 | return 0; | ||
869 | case V4L2_SEL_TGT_CROP: | ||
870 | sel->r.width = VGA_WIDTH; | ||
871 | sel->r.height = VGA_HEIGHT; | ||
872 | return 0; | ||
873 | default: | ||
874 | return -EINVAL; | ||
875 | } | ||
877 | } | 876 | } |
878 | 877 | ||
879 | static int ov772x_get_fmt(struct v4l2_subdev *sd, | 878 | static int ov772x_get_fmt(struct v4l2_subdev *sd, |
@@ -1030,13 +1029,12 @@ static int ov772x_g_mbus_config(struct v4l2_subdev *sd, | |||
1030 | 1029 | ||
1031 | static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { | 1030 | static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { |
1032 | .s_stream = ov772x_s_stream, | 1031 | .s_stream = ov772x_s_stream, |
1033 | .cropcap = ov772x_cropcap, | ||
1034 | .g_crop = ov772x_g_crop, | ||
1035 | .g_mbus_config = ov772x_g_mbus_config, | 1032 | .g_mbus_config = ov772x_g_mbus_config, |
1036 | }; | 1033 | }; |
1037 | 1034 | ||
1038 | static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = { | 1035 | static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = { |
1039 | .enum_mbus_code = ov772x_enum_mbus_code, | 1036 | .enum_mbus_code = ov772x_enum_mbus_code, |
1037 | .get_selection = ov772x_get_selection, | ||
1040 | .get_fmt = ov772x_get_fmt, | 1038 | .get_fmt = ov772x_get_fmt, |
1041 | .set_fmt = ov772x_set_fmt, | 1039 | .set_fmt = ov772x_set_fmt, |
1042 | }; | 1040 | }; |
diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index 8caae1c07541..8c93c57af71c 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c | |||
@@ -561,29 +561,25 @@ static int ov9640_enum_mbus_code(struct v4l2_subdev *sd, | |||
561 | return 0; | 561 | return 0; |
562 | } | 562 | } |
563 | 563 | ||
564 | static int ov9640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 564 | static int ov9640_get_selection(struct v4l2_subdev *sd, |
565 | { | 565 | struct v4l2_subdev_pad_config *cfg, |
566 | a->c.left = 0; | 566 | struct v4l2_subdev_selection *sel) |
567 | a->c.top = 0; | ||
568 | a->c.width = W_SXGA; | ||
569 | a->c.height = H_SXGA; | ||
570 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
571 | |||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
576 | { | 567 | { |
577 | a->bounds.left = 0; | 568 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
578 | a->bounds.top = 0; | 569 | return -EINVAL; |
579 | a->bounds.width = W_SXGA; | ||
580 | a->bounds.height = H_SXGA; | ||
581 | a->defrect = a->bounds; | ||
582 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
583 | a->pixelaspect.numerator = 1; | ||
584 | a->pixelaspect.denominator = 1; | ||
585 | 570 | ||
586 | return 0; | 571 | sel->r.left = 0; |
572 | sel->r.top = 0; | ||
573 | switch (sel->target) { | ||
574 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
575 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
576 | case V4L2_SEL_TGT_CROP: | ||
577 | sel->r.width = W_SXGA; | ||
578 | sel->r.height = H_SXGA; | ||
579 | return 0; | ||
580 | default: | ||
581 | return -EINVAL; | ||
582 | } | ||
587 | } | 583 | } |
588 | 584 | ||
589 | static int ov9640_video_probe(struct i2c_client *client) | 585 | static int ov9640_video_probe(struct i2c_client *client) |
@@ -667,13 +663,12 @@ static int ov9640_g_mbus_config(struct v4l2_subdev *sd, | |||
667 | 663 | ||
668 | static struct v4l2_subdev_video_ops ov9640_video_ops = { | 664 | static struct v4l2_subdev_video_ops ov9640_video_ops = { |
669 | .s_stream = ov9640_s_stream, | 665 | .s_stream = ov9640_s_stream, |
670 | .cropcap = ov9640_cropcap, | ||
671 | .g_crop = ov9640_g_crop, | ||
672 | .g_mbus_config = ov9640_g_mbus_config, | 666 | .g_mbus_config = ov9640_g_mbus_config, |
673 | }; | 667 | }; |
674 | 668 | ||
675 | static const struct v4l2_subdev_pad_ops ov9640_pad_ops = { | 669 | static const struct v4l2_subdev_pad_ops ov9640_pad_ops = { |
676 | .enum_mbus_code = ov9640_enum_mbus_code, | 670 | .enum_mbus_code = ov9640_enum_mbus_code, |
671 | .get_selection = ov9640_get_selection, | ||
677 | .set_fmt = ov9640_set_fmt, | 672 | .set_fmt = ov9640_set_fmt, |
678 | }; | 673 | }; |
679 | 674 | ||
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index 03a7fc7316ae..0da632d7d33a 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c | |||
@@ -737,29 +737,25 @@ static int ov9740_enum_mbus_code(struct v4l2_subdev *sd, | |||
737 | return 0; | 737 | return 0; |
738 | } | 738 | } |
739 | 739 | ||
740 | static int ov9740_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | 740 | static int ov9740_get_selection(struct v4l2_subdev *sd, |
741 | { | 741 | struct v4l2_subdev_pad_config *cfg, |
742 | a->bounds.left = 0; | 742 | struct v4l2_subdev_selection *sel) |
743 | a->bounds.top = 0; | ||
744 | a->bounds.width = OV9740_MAX_WIDTH; | ||
745 | a->bounds.height = OV9740_MAX_HEIGHT; | ||
746 | a->defrect = a->bounds; | ||
747 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
748 | a->pixelaspect.numerator = 1; | ||
749 | a->pixelaspect.denominator = 1; | ||
750 | |||
751 | return 0; | ||
752 | } | ||
753 | |||
754 | static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
755 | { | 743 | { |
756 | a->c.left = 0; | 744 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
757 | a->c.top = 0; | 745 | return -EINVAL; |
758 | a->c.width = OV9740_MAX_WIDTH; | ||
759 | a->c.height = OV9740_MAX_HEIGHT; | ||
760 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
761 | 746 | ||
762 | return 0; | 747 | switch (sel->target) { |
748 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
749 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
750 | case V4L2_SEL_TGT_CROP: | ||
751 | sel->r.left = 0; | ||
752 | sel->r.top = 0; | ||
753 | sel->r.width = OV9740_MAX_WIDTH; | ||
754 | sel->r.height = OV9740_MAX_HEIGHT; | ||
755 | return 0; | ||
756 | default: | ||
757 | return -EINVAL; | ||
758 | } | ||
763 | } | 759 | } |
764 | 760 | ||
765 | /* Set status of additional camera capabilities */ | 761 | /* Set status of additional camera capabilities */ |
@@ -914,8 +910,6 @@ static int ov9740_g_mbus_config(struct v4l2_subdev *sd, | |||
914 | 910 | ||
915 | static struct v4l2_subdev_video_ops ov9740_video_ops = { | 911 | static struct v4l2_subdev_video_ops ov9740_video_ops = { |
916 | .s_stream = ov9740_s_stream, | 912 | .s_stream = ov9740_s_stream, |
917 | .cropcap = ov9740_cropcap, | ||
918 | .g_crop = ov9740_g_crop, | ||
919 | .g_mbus_config = ov9740_g_mbus_config, | 913 | .g_mbus_config = ov9740_g_mbus_config, |
920 | }; | 914 | }; |
921 | 915 | ||
@@ -929,6 +923,7 @@ static struct v4l2_subdev_core_ops ov9740_core_ops = { | |||
929 | 923 | ||
930 | static const struct v4l2_subdev_pad_ops ov9740_pad_ops = { | 924 | static const struct v4l2_subdev_pad_ops ov9740_pad_ops = { |
931 | .enum_mbus_code = ov9740_enum_mbus_code, | 925 | .enum_mbus_code = ov9740_enum_mbus_code, |
926 | .get_selection = ov9740_get_selection, | ||
932 | .set_fmt = ov9740_set_fmt, | 927 | .set_fmt = ov9740_set_fmt, |
933 | }; | 928 | }; |
934 | 929 | ||
diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index aa7bfbb4ad71..bc8ec59a3fbd 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c | |||
@@ -538,15 +538,21 @@ static int rj54n1_commit(struct i2c_client *client) | |||
538 | static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h, | 538 | static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h, |
539 | s32 *out_w, s32 *out_h); | 539 | s32 *out_w, s32 *out_h); |
540 | 540 | ||
541 | static int rj54n1_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | 541 | static int rj54n1_set_selection(struct v4l2_subdev *sd, |
542 | struct v4l2_subdev_pad_config *cfg, | ||
543 | struct v4l2_subdev_selection *sel) | ||
542 | { | 544 | { |
543 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 545 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
544 | struct rj54n1 *rj54n1 = to_rj54n1(client); | 546 | struct rj54n1 *rj54n1 = to_rj54n1(client); |
545 | const struct v4l2_rect *rect = &a->c; | 547 | const struct v4l2_rect *rect = &sel->r; |
546 | int dummy = 0, output_w, output_h, | 548 | int dummy = 0, output_w, output_h, |
547 | input_w = rect->width, input_h = rect->height; | 549 | input_w = rect->width, input_h = rect->height; |
548 | int ret; | 550 | int ret; |
549 | 551 | ||
552 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || | ||
553 | sel->target != V4L2_SEL_TGT_CROP) | ||
554 | return -EINVAL; | ||
555 | |||
550 | /* arbitrary minimum width and height, edges unimportant */ | 556 | /* arbitrary minimum width and height, edges unimportant */ |
551 | soc_camera_limit_side(&dummy, &input_w, | 557 | soc_camera_limit_side(&dummy, &input_w, |
552 | RJ54N1_COLUMN_SKIP, 8, RJ54N1_MAX_WIDTH); | 558 | RJ54N1_COLUMN_SKIP, 8, RJ54N1_MAX_WIDTH); |
@@ -573,29 +579,30 @@ static int rj54n1_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | |||
573 | return 0; | 579 | return 0; |
574 | } | 580 | } |
575 | 581 | ||
576 | static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 582 | static int rj54n1_get_selection(struct v4l2_subdev *sd, |
583 | struct v4l2_subdev_pad_config *cfg, | ||
584 | struct v4l2_subdev_selection *sel) | ||
577 | { | 585 | { |
578 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 586 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
579 | struct rj54n1 *rj54n1 = to_rj54n1(client); | 587 | struct rj54n1 *rj54n1 = to_rj54n1(client); |
580 | 588 | ||
581 | a->c = rj54n1->rect; | 589 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
582 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 590 | return -EINVAL; |
583 | |||
584 | return 0; | ||
585 | } | ||
586 | |||
587 | static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
588 | { | ||
589 | a->bounds.left = RJ54N1_COLUMN_SKIP; | ||
590 | a->bounds.top = RJ54N1_ROW_SKIP; | ||
591 | a->bounds.width = RJ54N1_MAX_WIDTH; | ||
592 | a->bounds.height = RJ54N1_MAX_HEIGHT; | ||
593 | a->defrect = a->bounds; | ||
594 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
595 | a->pixelaspect.numerator = 1; | ||
596 | a->pixelaspect.denominator = 1; | ||
597 | 591 | ||
598 | return 0; | 592 | switch (sel->target) { |
593 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
594 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
595 | sel->r.left = RJ54N1_COLUMN_SKIP; | ||
596 | sel->r.top = RJ54N1_ROW_SKIP; | ||
597 | sel->r.width = RJ54N1_MAX_WIDTH; | ||
598 | sel->r.height = RJ54N1_MAX_HEIGHT; | ||
599 | return 0; | ||
600 | case V4L2_SEL_TGT_CROP: | ||
601 | sel->r = rj54n1->rect; | ||
602 | return 0; | ||
603 | default: | ||
604 | return -EINVAL; | ||
605 | } | ||
599 | } | 606 | } |
600 | 607 | ||
601 | static int rj54n1_get_fmt(struct v4l2_subdev *sd, | 608 | static int rj54n1_get_fmt(struct v4l2_subdev *sd, |
@@ -1246,15 +1253,14 @@ static int rj54n1_s_mbus_config(struct v4l2_subdev *sd, | |||
1246 | 1253 | ||
1247 | static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { | 1254 | static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { |
1248 | .s_stream = rj54n1_s_stream, | 1255 | .s_stream = rj54n1_s_stream, |
1249 | .g_crop = rj54n1_g_crop, | ||
1250 | .s_crop = rj54n1_s_crop, | ||
1251 | .cropcap = rj54n1_cropcap, | ||
1252 | .g_mbus_config = rj54n1_g_mbus_config, | 1256 | .g_mbus_config = rj54n1_g_mbus_config, |
1253 | .s_mbus_config = rj54n1_s_mbus_config, | 1257 | .s_mbus_config = rj54n1_s_mbus_config, |
1254 | }; | 1258 | }; |
1255 | 1259 | ||
1256 | static const struct v4l2_subdev_pad_ops rj54n1_subdev_pad_ops = { | 1260 | static const struct v4l2_subdev_pad_ops rj54n1_subdev_pad_ops = { |
1257 | .enum_mbus_code = rj54n1_enum_mbus_code, | 1261 | .enum_mbus_code = rj54n1_enum_mbus_code, |
1262 | .get_selection = rj54n1_get_selection, | ||
1263 | .set_selection = rj54n1_set_selection, | ||
1258 | .get_fmt = rj54n1_get_fmt, | 1264 | .get_fmt = rj54n1_get_fmt, |
1259 | .set_fmt = rj54n1_set_fmt, | 1265 | .set_fmt = rj54n1_set_fmt, |
1260 | }; | 1266 | }; |
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index 06aff81787a7..4002c07f3857 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c | |||
@@ -676,44 +676,28 @@ tw9910_set_fmt_error: | |||
676 | return ret; | 676 | return ret; |
677 | } | 677 | } |
678 | 678 | ||
679 | static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 679 | static int tw9910_get_selection(struct v4l2_subdev *sd, |
680 | struct v4l2_subdev_pad_config *cfg, | ||
681 | struct v4l2_subdev_selection *sel) | ||
680 | { | 682 | { |
681 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 683 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
682 | struct tw9910_priv *priv = to_tw9910(client); | 684 | struct tw9910_priv *priv = to_tw9910(client); |
683 | 685 | ||
684 | a->c.left = 0; | 686 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
685 | a->c.top = 0; | 687 | return -EINVAL; |
686 | if (priv->norm & V4L2_STD_NTSC) { | 688 | /* Only CROP, CROP_DEFAULT and CROP_BOUNDS are supported */ |
687 | a->c.width = 640; | 689 | if (sel->target > V4L2_SEL_TGT_CROP_BOUNDS) |
688 | a->c.height = 480; | 690 | return -EINVAL; |
689 | } else { | ||
690 | a->c.width = 768; | ||
691 | a->c.height = 576; | ||
692 | } | ||
693 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
699 | { | ||
700 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
701 | struct tw9910_priv *priv = to_tw9910(client); | ||
702 | 691 | ||
703 | a->bounds.left = 0; | 692 | sel->r.left = 0; |
704 | a->bounds.top = 0; | 693 | sel->r.top = 0; |
705 | if (priv->norm & V4L2_STD_NTSC) { | 694 | if (priv->norm & V4L2_STD_NTSC) { |
706 | a->bounds.width = 640; | 695 | sel->r.width = 640; |
707 | a->bounds.height = 480; | 696 | sel->r.height = 480; |
708 | } else { | 697 | } else { |
709 | a->bounds.width = 768; | 698 | sel->r.width = 768; |
710 | a->bounds.height = 576; | 699 | sel->r.height = 576; |
711 | } | 700 | } |
712 | a->defrect = a->bounds; | ||
713 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
714 | a->pixelaspect.numerator = 1; | ||
715 | a->pixelaspect.denominator = 1; | ||
716 | |||
717 | return 0; | 701 | return 0; |
718 | } | 702 | } |
719 | 703 | ||
@@ -921,8 +905,6 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { | |||
921 | .s_std = tw9910_s_std, | 905 | .s_std = tw9910_s_std, |
922 | .g_std = tw9910_g_std, | 906 | .g_std = tw9910_g_std, |
923 | .s_stream = tw9910_s_stream, | 907 | .s_stream = tw9910_s_stream, |
924 | .cropcap = tw9910_cropcap, | ||
925 | .g_crop = tw9910_g_crop, | ||
926 | .g_mbus_config = tw9910_g_mbus_config, | 908 | .g_mbus_config = tw9910_g_mbus_config, |
927 | .s_mbus_config = tw9910_s_mbus_config, | 909 | .s_mbus_config = tw9910_s_mbus_config, |
928 | .g_tvnorms = tw9910_g_tvnorms, | 910 | .g_tvnorms = tw9910_g_tvnorms, |
@@ -930,6 +912,7 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { | |||
930 | 912 | ||
931 | static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = { | 913 | static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = { |
932 | .enum_mbus_code = tw9910_enum_mbus_code, | 914 | .enum_mbus_code = tw9910_enum_mbus_code, |
915 | .get_selection = tw9910_get_selection, | ||
933 | .get_fmt = tw9910_get_fmt, | 916 | .get_fmt = tw9910_get_fmt, |
934 | .set_fmt = tw9910_set_fmt, | 917 | .set_fmt = tw9910_set_fmt, |
935 | }; | 918 | }; |
diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c index 73fc42bc2de6..42340e364cea 100644 --- a/drivers/media/i2c/ths8200.c +++ b/drivers/media/i2c/ths8200.c | |||
@@ -499,7 +499,6 @@ MODULE_DEVICE_TABLE(of, ths8200_of_match); | |||
499 | 499 | ||
500 | static struct i2c_driver ths8200_driver = { | 500 | static struct i2c_driver ths8200_driver = { |
501 | .driver = { | 501 | .driver = { |
502 | .owner = THIS_MODULE, | ||
503 | .name = "ths8200", | 502 | .name = "ths8200", |
504 | .of_match_table = of_match_ptr(ths8200_of_match), | 503 | .of_match_table = of_match_ptr(ths8200_of_match), |
505 | }, | 504 | }, |
diff --git a/drivers/media/i2c/tlv320aic23b.c b/drivers/media/i2c/tlv320aic23b.c index 0370dd89f1fc..2e06c06cac9b 100644 --- a/drivers/media/i2c/tlv320aic23b.c +++ b/drivers/media/i2c/tlv320aic23b.c | |||
@@ -210,7 +210,6 @@ MODULE_DEVICE_TABLE(i2c, tlv320aic23b_id); | |||
210 | 210 | ||
211 | static struct i2c_driver tlv320aic23b_driver = { | 211 | static struct i2c_driver tlv320aic23b_driver = { |
212 | .driver = { | 212 | .driver = { |
213 | .owner = THIS_MODULE, | ||
214 | .name = "tlv320aic23b", | 213 | .name = "tlv320aic23b", |
215 | }, | 214 | }, |
216 | .probe = tlv320aic23b_probe, | 215 | .probe = tlv320aic23b_probe, |
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 7cdd94842938..d5c9347f4c6d 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c | |||
@@ -977,7 +977,7 @@ static const struct v4l2_subdev_ops tvp514x_ops = { | |||
977 | .pad = &tvp514x_pad_ops, | 977 | .pad = &tvp514x_pad_ops, |
978 | }; | 978 | }; |
979 | 979 | ||
980 | static struct tvp514x_decoder tvp514x_dev = { | 980 | static const struct tvp514x_decoder tvp514x_dev = { |
981 | .streaming = 0, | 981 | .streaming = 0, |
982 | .fmt_list = tvp514x_fmt_list, | 982 | .fmt_list = tvp514x_fmt_list, |
983 | .num_fmts = ARRAY_SIZE(tvp514x_fmt_list), | 983 | .num_fmts = ARRAY_SIZE(tvp514x_fmt_list), |
@@ -1233,7 +1233,6 @@ MODULE_DEVICE_TABLE(of, tvp514x_of_match); | |||
1233 | static struct i2c_driver tvp514x_driver = { | 1233 | static struct i2c_driver tvp514x_driver = { |
1234 | .driver = { | 1234 | .driver = { |
1235 | .of_match_table = of_match_ptr(tvp514x_of_match), | 1235 | .of_match_table = of_match_ptr(tvp514x_of_match), |
1236 | .owner = THIS_MODULE, | ||
1237 | .name = TVP514X_MODULE_NAME, | 1236 | .name = TVP514X_MODULE_NAME, |
1238 | }, | 1237 | }, |
1239 | .probe = tvp514x_probe, | 1238 | .probe = tvp514x_probe, |
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 0b6d46c453bf..4740da39d698 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c | |||
@@ -871,19 +871,22 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd, | |||
871 | return 0; | 871 | return 0; |
872 | } | 872 | } |
873 | 873 | ||
874 | static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | 874 | static int tvp5150_set_selection(struct v4l2_subdev *sd, |
875 | struct v4l2_subdev_pad_config *cfg, | ||
876 | struct v4l2_subdev_selection *sel) | ||
875 | { | 877 | { |
876 | struct v4l2_rect rect = a->c; | ||
877 | struct tvp5150 *decoder = to_tvp5150(sd); | 878 | struct tvp5150 *decoder = to_tvp5150(sd); |
879 | struct v4l2_rect rect = sel->r; | ||
878 | v4l2_std_id std; | 880 | v4l2_std_id std; |
879 | unsigned int hmax; | 881 | int hmax; |
882 | |||
883 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || | ||
884 | sel->target != V4L2_SEL_TGT_CROP) | ||
885 | return -EINVAL; | ||
880 | 886 | ||
881 | v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n", | 887 | v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n", |
882 | __func__, rect.left, rect.top, rect.width, rect.height); | 888 | __func__, rect.left, rect.top, rect.width, rect.height); |
883 | 889 | ||
884 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
885 | return -EINVAL; | ||
886 | |||
887 | /* tvp5150 has some special limits */ | 890 | /* tvp5150 has some special limits */ |
888 | rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); | 891 | rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); |
889 | rect.width = clamp_t(unsigned int, rect.width, | 892 | rect.width = clamp_t(unsigned int, rect.width, |
@@ -924,44 +927,39 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) | |||
924 | return 0; | 927 | return 0; |
925 | } | 928 | } |
926 | 929 | ||
927 | static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 930 | static int tvp5150_get_selection(struct v4l2_subdev *sd, |
928 | { | 931 | struct v4l2_subdev_pad_config *cfg, |
929 | struct tvp5150 *decoder = to_tvp5150(sd); | 932 | struct v4l2_subdev_selection *sel) |
930 | |||
931 | a->c = decoder->rect; | ||
932 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
933 | |||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
938 | { | 933 | { |
939 | struct tvp5150 *decoder = to_tvp5150(sd); | 934 | struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd); |
940 | v4l2_std_id std; | 935 | v4l2_std_id std; |
941 | 936 | ||
942 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 937 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
943 | return -EINVAL; | 938 | return -EINVAL; |
944 | 939 | ||
945 | a->bounds.left = 0; | 940 | switch (sel->target) { |
946 | a->bounds.top = 0; | 941 | case V4L2_SEL_TGT_CROP_BOUNDS: |
947 | a->bounds.width = TVP5150_H_MAX; | 942 | case V4L2_SEL_TGT_CROP_DEFAULT: |
948 | 943 | sel->r.left = 0; | |
949 | /* Calculate height based on current standard */ | 944 | sel->r.top = 0; |
950 | if (decoder->norm == V4L2_STD_ALL) | 945 | sel->r.width = TVP5150_H_MAX; |
951 | std = tvp5150_read_std(sd); | 946 | |
952 | else | 947 | /* Calculate height based on current standard */ |
953 | std = decoder->norm; | 948 | if (decoder->norm == V4L2_STD_ALL) |
954 | 949 | std = tvp5150_read_std(sd); | |
955 | if (std & V4L2_STD_525_60) | 950 | else |
956 | a->bounds.height = TVP5150_V_MAX_525_60; | 951 | std = decoder->norm; |
957 | else | 952 | if (std & V4L2_STD_525_60) |
958 | a->bounds.height = TVP5150_V_MAX_OTHERS; | 953 | sel->r.height = TVP5150_V_MAX_525_60; |
959 | 954 | else | |
960 | a->defrect = a->bounds; | 955 | sel->r.height = TVP5150_V_MAX_OTHERS; |
961 | a->pixelaspect.numerator = 1; | 956 | return 0; |
962 | a->pixelaspect.denominator = 1; | 957 | case V4L2_SEL_TGT_CROP: |
963 | 958 | sel->r = decoder->rect; | |
964 | return 0; | 959 | return 0; |
960 | default: | ||
961 | return -EINVAL; | ||
962 | } | ||
965 | } | 963 | } |
966 | 964 | ||
967 | static int tvp5150_g_mbus_config(struct v4l2_subdev *sd, | 965 | static int tvp5150_g_mbus_config(struct v4l2_subdev *sd, |
@@ -1173,7 +1171,7 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | |||
1173 | return 0; | 1171 | return 0; |
1174 | } | 1172 | } |
1175 | 1173 | ||
1176 | static int tvp5150_registered_async(struct v4l2_subdev *sd) | 1174 | static int tvp5150_registered(struct v4l2_subdev *sd) |
1177 | { | 1175 | { |
1178 | #ifdef CONFIG_MEDIA_CONTROLLER | 1176 | #ifdef CONFIG_MEDIA_CONTROLLER |
1179 | struct tvp5150 *decoder = to_tvp5150(sd); | 1177 | struct tvp5150 *decoder = to_tvp5150(sd); |
@@ -1222,7 +1220,6 @@ static const struct v4l2_subdev_core_ops tvp5150_core_ops = { | |||
1222 | .g_register = tvp5150_g_register, | 1220 | .g_register = tvp5150_g_register, |
1223 | .s_register = tvp5150_s_register, | 1221 | .s_register = tvp5150_s_register, |
1224 | #endif | 1222 | #endif |
1225 | .registered_async = tvp5150_registered_async, | ||
1226 | }; | 1223 | }; |
1227 | 1224 | ||
1228 | static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { | 1225 | static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { |
@@ -1233,9 +1230,6 @@ static const struct v4l2_subdev_video_ops tvp5150_video_ops = { | |||
1233 | .s_std = tvp5150_s_std, | 1230 | .s_std = tvp5150_s_std, |
1234 | .s_stream = tvp5150_s_stream, | 1231 | .s_stream = tvp5150_s_stream, |
1235 | .s_routing = tvp5150_s_routing, | 1232 | .s_routing = tvp5150_s_routing, |
1236 | .s_crop = tvp5150_s_crop, | ||
1237 | .g_crop = tvp5150_g_crop, | ||
1238 | .cropcap = tvp5150_cropcap, | ||
1239 | .g_mbus_config = tvp5150_g_mbus_config, | 1233 | .g_mbus_config = tvp5150_g_mbus_config, |
1240 | }; | 1234 | }; |
1241 | 1235 | ||
@@ -1251,6 +1245,8 @@ static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { | |||
1251 | .enum_frame_size = tvp5150_enum_frame_size, | 1245 | .enum_frame_size = tvp5150_enum_frame_size, |
1252 | .set_fmt = tvp5150_fill_fmt, | 1246 | .set_fmt = tvp5150_fill_fmt, |
1253 | .get_fmt = tvp5150_fill_fmt, | 1247 | .get_fmt = tvp5150_fill_fmt, |
1248 | .get_selection = tvp5150_get_selection, | ||
1249 | .set_selection = tvp5150_set_selection, | ||
1254 | }; | 1250 | }; |
1255 | 1251 | ||
1256 | static const struct v4l2_subdev_ops tvp5150_ops = { | 1252 | static const struct v4l2_subdev_ops tvp5150_ops = { |
@@ -1261,6 +1257,10 @@ static const struct v4l2_subdev_ops tvp5150_ops = { | |||
1261 | .pad = &tvp5150_pad_ops, | 1257 | .pad = &tvp5150_pad_ops, |
1262 | }; | 1258 | }; |
1263 | 1259 | ||
1260 | static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = { | ||
1261 | .registered = tvp5150_registered, | ||
1262 | }; | ||
1263 | |||
1264 | 1264 | ||
1265 | /**************************************************************************** | 1265 | /**************************************************************************** |
1266 | I2C Client & Driver | 1266 | I2C Client & Driver |
@@ -1474,6 +1474,7 @@ static int tvp5150_probe(struct i2c_client *c, | |||
1474 | } | 1474 | } |
1475 | 1475 | ||
1476 | v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); | 1476 | v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); |
1477 | sd->internal_ops = &tvp5150_internal_ops; | ||
1477 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 1478 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
1478 | 1479 | ||
1479 | #if defined(CONFIG_MEDIA_CONTROLLER) | 1480 | #if defined(CONFIG_MEDIA_CONTROLLER) |
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 4df640c3aa40..3dc3341c4896 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c | |||
@@ -1086,7 +1086,6 @@ MODULE_DEVICE_TABLE(of, tvp7002_of_match); | |||
1086 | static struct i2c_driver tvp7002_driver = { | 1086 | static struct i2c_driver tvp7002_driver = { |
1087 | .driver = { | 1087 | .driver = { |
1088 | .of_match_table = of_match_ptr(tvp7002_of_match), | 1088 | .of_match_table = of_match_ptr(tvp7002_of_match), |
1089 | .owner = THIS_MODULE, | ||
1090 | .name = TVP7002_MODULE_NAME, | 1089 | .name = TVP7002_MODULE_NAME, |
1091 | }, | 1090 | }, |
1092 | .probe = tvp7002_probe, | 1091 | .probe = tvp7002_probe, |
diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 4c72a18c0b8c..be4cb7a8bdeb 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c | |||
@@ -863,7 +863,6 @@ MODULE_DEVICE_TABLE(i2c, vs6624_id); | |||
863 | 863 | ||
864 | static struct i2c_driver vs6624_driver = { | 864 | static struct i2c_driver vs6624_driver = { |
865 | .driver = { | 865 | .driver = { |
866 | .owner = THIS_MODULE, | ||
867 | .name = "vs6624", | 866 | .name = "vs6624", |
868 | }, | 867 | }, |
869 | .probe = vs6624_probe, | 868 | .probe = vs6624_probe, |
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 1795abeda658..2783531f9fc0 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c | |||
@@ -59,27 +59,24 @@ static int media_device_close(struct file *filp) | |||
59 | } | 59 | } |
60 | 60 | ||
61 | static int media_device_get_info(struct media_device *dev, | 61 | static int media_device_get_info(struct media_device *dev, |
62 | struct media_device_info __user *__info) | 62 | struct media_device_info *info) |
63 | { | 63 | { |
64 | struct media_device_info info; | 64 | memset(info, 0, sizeof(*info)); |
65 | |||
66 | memset(&info, 0, sizeof(info)); | ||
67 | 65 | ||
68 | if (dev->driver_name[0]) | 66 | if (dev->driver_name[0]) |
69 | strlcpy(info.driver, dev->driver_name, sizeof(info.driver)); | 67 | strlcpy(info->driver, dev->driver_name, sizeof(info->driver)); |
70 | else | 68 | else |
71 | strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver)); | 69 | strlcpy(info->driver, dev->dev->driver->name, |
70 | sizeof(info->driver)); | ||
72 | 71 | ||
73 | strlcpy(info.model, dev->model, sizeof(info.model)); | 72 | strlcpy(info->model, dev->model, sizeof(info->model)); |
74 | strlcpy(info.serial, dev->serial, sizeof(info.serial)); | 73 | strlcpy(info->serial, dev->serial, sizeof(info->serial)); |
75 | strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info)); | 74 | strlcpy(info->bus_info, dev->bus_info, sizeof(info->bus_info)); |
76 | 75 | ||
77 | info.media_version = MEDIA_API_VERSION; | 76 | info->media_version = MEDIA_API_VERSION; |
78 | info.hw_revision = dev->hw_revision; | 77 | info->hw_revision = dev->hw_revision; |
79 | info.driver_version = dev->driver_version; | 78 | info->driver_version = dev->driver_version; |
80 | 79 | ||
81 | if (copy_to_user(__info, &info, sizeof(*__info))) | ||
82 | return -EFAULT; | ||
83 | return 0; | 80 | return 0; |
84 | } | 81 | } |
85 | 82 | ||
@@ -101,29 +98,25 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id) | |||
101 | } | 98 | } |
102 | 99 | ||
103 | static long media_device_enum_entities(struct media_device *mdev, | 100 | static long media_device_enum_entities(struct media_device *mdev, |
104 | struct media_entity_desc __user *uent) | 101 | struct media_entity_desc *entd) |
105 | { | 102 | { |
106 | struct media_entity *ent; | 103 | struct media_entity *ent; |
107 | struct media_entity_desc u_ent; | ||
108 | |||
109 | memset(&u_ent, 0, sizeof(u_ent)); | ||
110 | if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id))) | ||
111 | return -EFAULT; | ||
112 | |||
113 | ent = find_entity(mdev, u_ent.id); | ||
114 | 104 | ||
105 | ent = find_entity(mdev, entd->id); | ||
115 | if (ent == NULL) | 106 | if (ent == NULL) |
116 | return -EINVAL; | 107 | return -EINVAL; |
117 | 108 | ||
118 | u_ent.id = media_entity_id(ent); | 109 | memset(entd, 0, sizeof(*entd)); |
110 | |||
111 | entd->id = media_entity_id(ent); | ||
119 | if (ent->name) | 112 | if (ent->name) |
120 | strlcpy(u_ent.name, ent->name, sizeof(u_ent.name)); | 113 | strlcpy(entd->name, ent->name, sizeof(entd->name)); |
121 | u_ent.type = ent->function; | 114 | entd->type = ent->function; |
122 | u_ent.revision = 0; /* Unused */ | 115 | entd->revision = 0; /* Unused */ |
123 | u_ent.flags = ent->flags; | 116 | entd->flags = ent->flags; |
124 | u_ent.group_id = 0; /* Unused */ | 117 | entd->group_id = 0; /* Unused */ |
125 | u_ent.pads = ent->num_pads; | 118 | entd->pads = ent->num_pads; |
126 | u_ent.links = ent->num_links - ent->num_backlinks; | 119 | entd->links = ent->num_links - ent->num_backlinks; |
127 | 120 | ||
128 | /* | 121 | /* |
129 | * Workaround for a bug at media-ctl <= v1.10 that makes it to | 122 | * Workaround for a bug at media-ctl <= v1.10 that makes it to |
@@ -139,14 +132,13 @@ static long media_device_enum_entities(struct media_device *mdev, | |||
139 | if (ent->function < MEDIA_ENT_F_OLD_BASE || | 132 | if (ent->function < MEDIA_ENT_F_OLD_BASE || |
140 | ent->function > MEDIA_ENT_T_DEVNODE_UNKNOWN) { | 133 | ent->function > MEDIA_ENT_T_DEVNODE_UNKNOWN) { |
141 | if (is_media_entity_v4l2_subdev(ent)) | 134 | if (is_media_entity_v4l2_subdev(ent)) |
142 | u_ent.type = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; | 135 | entd->type = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; |
143 | else if (ent->function != MEDIA_ENT_F_IO_V4L) | 136 | else if (ent->function != MEDIA_ENT_F_IO_V4L) |
144 | u_ent.type = MEDIA_ENT_T_DEVNODE_UNKNOWN; | 137 | entd->type = MEDIA_ENT_T_DEVNODE_UNKNOWN; |
145 | } | 138 | } |
146 | 139 | ||
147 | memcpy(&u_ent.raw, &ent->info, sizeof(ent->info)); | 140 | memcpy(&entd->raw, &ent->info, sizeof(ent->info)); |
148 | if (copy_to_user(uent, &u_ent, sizeof(u_ent))) | 141 | |
149 | return -EFAULT; | ||
150 | return 0; | 142 | return 0; |
151 | } | 143 | } |
152 | 144 | ||
@@ -158,8 +150,8 @@ static void media_device_kpad_to_upad(const struct media_pad *kpad, | |||
158 | upad->flags = kpad->flags; | 150 | upad->flags = kpad->flags; |
159 | } | 151 | } |
160 | 152 | ||
161 | static long __media_device_enum_links(struct media_device *mdev, | 153 | static long media_device_enum_links(struct media_device *mdev, |
162 | struct media_links_enum *links) | 154 | struct media_links_enum *links) |
163 | { | 155 | { |
164 | struct media_entity *entity; | 156 | struct media_entity *entity; |
165 | 157 | ||
@@ -206,64 +198,35 @@ static long __media_device_enum_links(struct media_device *mdev, | |||
206 | return 0; | 198 | return 0; |
207 | } | 199 | } |
208 | 200 | ||
209 | static long media_device_enum_links(struct media_device *mdev, | ||
210 | struct media_links_enum __user *ulinks) | ||
211 | { | ||
212 | struct media_links_enum links; | ||
213 | int rval; | ||
214 | |||
215 | if (copy_from_user(&links, ulinks, sizeof(links))) | ||
216 | return -EFAULT; | ||
217 | |||
218 | rval = __media_device_enum_links(mdev, &links); | ||
219 | if (rval < 0) | ||
220 | return rval; | ||
221 | |||
222 | if (copy_to_user(ulinks, &links, sizeof(*ulinks))) | ||
223 | return -EFAULT; | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static long media_device_setup_link(struct media_device *mdev, | 201 | static long media_device_setup_link(struct media_device *mdev, |
229 | struct media_link_desc __user *_ulink) | 202 | struct media_link_desc *linkd) |
230 | { | 203 | { |
231 | struct media_link *link = NULL; | 204 | struct media_link *link = NULL; |
232 | struct media_link_desc ulink; | ||
233 | struct media_entity *source; | 205 | struct media_entity *source; |
234 | struct media_entity *sink; | 206 | struct media_entity *sink; |
235 | int ret; | ||
236 | |||
237 | if (copy_from_user(&ulink, _ulink, sizeof(ulink))) | ||
238 | return -EFAULT; | ||
239 | 207 | ||
240 | /* Find the source and sink entities and link. | 208 | /* Find the source and sink entities and link. |
241 | */ | 209 | */ |
242 | source = find_entity(mdev, ulink.source.entity); | 210 | source = find_entity(mdev, linkd->source.entity); |
243 | sink = find_entity(mdev, ulink.sink.entity); | 211 | sink = find_entity(mdev, linkd->sink.entity); |
244 | 212 | ||
245 | if (source == NULL || sink == NULL) | 213 | if (source == NULL || sink == NULL) |
246 | return -EINVAL; | 214 | return -EINVAL; |
247 | 215 | ||
248 | if (ulink.source.index >= source->num_pads || | 216 | if (linkd->source.index >= source->num_pads || |
249 | ulink.sink.index >= sink->num_pads) | 217 | linkd->sink.index >= sink->num_pads) |
250 | return -EINVAL; | 218 | return -EINVAL; |
251 | 219 | ||
252 | link = media_entity_find_link(&source->pads[ulink.source.index], | 220 | link = media_entity_find_link(&source->pads[linkd->source.index], |
253 | &sink->pads[ulink.sink.index]); | 221 | &sink->pads[linkd->sink.index]); |
254 | if (link == NULL) | 222 | if (link == NULL) |
255 | return -EINVAL; | 223 | return -EINVAL; |
256 | 224 | ||
257 | /* Setup the link on both entities. */ | 225 | /* Setup the link on both entities. */ |
258 | ret = __media_entity_setup_link(link, ulink.flags); | 226 | return __media_entity_setup_link(link, linkd->flags); |
259 | |||
260 | if (copy_to_user(_ulink, &ulink, sizeof(ulink))) | ||
261 | return -EFAULT; | ||
262 | |||
263 | return ret; | ||
264 | } | 227 | } |
265 | 228 | ||
266 | static long __media_device_get_topology(struct media_device *mdev, | 229 | static long media_device_get_topology(struct media_device *mdev, |
267 | struct media_v2_topology *topo) | 230 | struct media_v2_topology *topo) |
268 | { | 231 | { |
269 | struct media_entity *entity; | 232 | struct media_entity *entity; |
@@ -400,63 +363,98 @@ static long __media_device_get_topology(struct media_device *mdev, | |||
400 | return ret; | 363 | return ret; |
401 | } | 364 | } |
402 | 365 | ||
403 | static long media_device_get_topology(struct media_device *mdev, | 366 | static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd) |
404 | struct media_v2_topology __user *utopo) | ||
405 | { | 367 | { |
406 | struct media_v2_topology ktopo; | 368 | /* All media IOCTLs are _IOWR() */ |
407 | int ret; | 369 | if (copy_from_user(karg, uarg, _IOC_SIZE(cmd))) |
408 | |||
409 | if (copy_from_user(&ktopo, utopo, sizeof(ktopo))) | ||
410 | return -EFAULT; | 370 | return -EFAULT; |
411 | 371 | ||
412 | ret = __media_device_get_topology(mdev, &ktopo); | 372 | return 0; |
413 | if (ret < 0) | 373 | } |
414 | return ret; | ||
415 | 374 | ||
416 | if (copy_to_user(utopo, &ktopo, sizeof(*utopo))) | 375 | static long copy_arg_to_user(void __user *uarg, void *karg, unsigned int cmd) |
376 | { | ||
377 | /* All media IOCTLs are _IOWR() */ | ||
378 | if (copy_to_user(uarg, karg, _IOC_SIZE(cmd))) | ||
417 | return -EFAULT; | 379 | return -EFAULT; |
418 | 380 | ||
419 | return 0; | 381 | return 0; |
420 | } | 382 | } |
421 | 383 | ||
384 | /* Do acquire the graph mutex */ | ||
385 | #define MEDIA_IOC_FL_GRAPH_MUTEX BIT(0) | ||
386 | |||
387 | #define MEDIA_IOC_ARG(__cmd, func, fl, from_user, to_user) \ | ||
388 | [_IOC_NR(MEDIA_IOC_##__cmd)] = { \ | ||
389 | .cmd = MEDIA_IOC_##__cmd, \ | ||
390 | .fn = (long (*)(struct media_device *, void *))func, \ | ||
391 | .flags = fl, \ | ||
392 | .arg_from_user = from_user, \ | ||
393 | .arg_to_user = to_user, \ | ||
394 | } | ||
395 | |||
396 | #define MEDIA_IOC(__cmd, func, fl) \ | ||
397 | MEDIA_IOC_ARG(__cmd, func, fl, copy_arg_from_user, copy_arg_to_user) | ||
398 | |||
399 | /* the table is indexed by _IOC_NR(cmd) */ | ||
400 | struct media_ioctl_info { | ||
401 | unsigned int cmd; | ||
402 | unsigned short flags; | ||
403 | long (*fn)(struct media_device *dev, void *arg); | ||
404 | long (*arg_from_user)(void *karg, void __user *uarg, unsigned int cmd); | ||
405 | long (*arg_to_user)(void __user *uarg, void *karg, unsigned int cmd); | ||
406 | }; | ||
407 | |||
408 | static const struct media_ioctl_info ioctl_info[] = { | ||
409 | MEDIA_IOC(DEVICE_INFO, media_device_get_info, MEDIA_IOC_FL_GRAPH_MUTEX), | ||
410 | MEDIA_IOC(ENUM_ENTITIES, media_device_enum_entities, MEDIA_IOC_FL_GRAPH_MUTEX), | ||
411 | MEDIA_IOC(ENUM_LINKS, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX), | ||
412 | MEDIA_IOC(SETUP_LINK, media_device_setup_link, MEDIA_IOC_FL_GRAPH_MUTEX), | ||
413 | MEDIA_IOC(G_TOPOLOGY, media_device_get_topology, MEDIA_IOC_FL_GRAPH_MUTEX), | ||
414 | }; | ||
415 | |||
422 | static long media_device_ioctl(struct file *filp, unsigned int cmd, | 416 | static long media_device_ioctl(struct file *filp, unsigned int cmd, |
423 | unsigned long arg) | 417 | unsigned long __arg) |
424 | { | 418 | { |
425 | struct media_devnode *devnode = media_devnode_data(filp); | 419 | struct media_devnode *devnode = media_devnode_data(filp); |
426 | struct media_device *dev = devnode->media_dev; | 420 | struct media_device *dev = devnode->media_dev; |
421 | const struct media_ioctl_info *info; | ||
422 | void __user *arg = (void __user *)__arg; | ||
423 | char __karg[256], *karg = __karg; | ||
427 | long ret; | 424 | long ret; |
428 | 425 | ||
429 | mutex_lock(&dev->graph_mutex); | 426 | if (_IOC_NR(cmd) >= ARRAY_SIZE(ioctl_info) |
430 | switch (cmd) { | 427 | || ioctl_info[_IOC_NR(cmd)].cmd != cmd) |
431 | case MEDIA_IOC_DEVICE_INFO: | 428 | return -ENOIOCTLCMD; |
432 | ret = media_device_get_info(dev, | ||
433 | (struct media_device_info __user *)arg); | ||
434 | break; | ||
435 | 429 | ||
436 | case MEDIA_IOC_ENUM_ENTITIES: | 430 | info = &ioctl_info[_IOC_NR(cmd)]; |
437 | ret = media_device_enum_entities(dev, | ||
438 | (struct media_entity_desc __user *)arg); | ||
439 | break; | ||
440 | 431 | ||
441 | case MEDIA_IOC_ENUM_LINKS: | 432 | if (_IOC_SIZE(info->cmd) > sizeof(__karg)) { |
442 | ret = media_device_enum_links(dev, | 433 | karg = kmalloc(_IOC_SIZE(info->cmd), GFP_KERNEL); |
443 | (struct media_links_enum __user *)arg); | 434 | if (!karg) |
444 | break; | 435 | return -ENOMEM; |
436 | } | ||
445 | 437 | ||
446 | case MEDIA_IOC_SETUP_LINK: | 438 | if (info->arg_from_user) { |
447 | ret = media_device_setup_link(dev, | 439 | ret = info->arg_from_user(karg, arg, cmd); |
448 | (struct media_link_desc __user *)arg); | 440 | if (ret) |
449 | break; | 441 | goto out_free; |
442 | } | ||
450 | 443 | ||
451 | case MEDIA_IOC_G_TOPOLOGY: | 444 | if (info->flags & MEDIA_IOC_FL_GRAPH_MUTEX) |
452 | ret = media_device_get_topology(dev, | 445 | mutex_lock(&dev->graph_mutex); |
453 | (struct media_v2_topology __user *)arg); | ||
454 | break; | ||
455 | 446 | ||
456 | default: | 447 | ret = info->fn(dev, karg); |
457 | ret = -ENOIOCTLCMD; | 448 | |
458 | } | 449 | if (info->flags & MEDIA_IOC_FL_GRAPH_MUTEX) |
459 | mutex_unlock(&dev->graph_mutex); | 450 | mutex_unlock(&dev->graph_mutex); |
451 | |||
452 | if (!ret && info->arg_to_user) | ||
453 | ret = info->arg_to_user(arg, karg, cmd); | ||
454 | |||
455 | out_free: | ||
456 | if (karg != __karg) | ||
457 | kfree(karg); | ||
460 | 458 | ||
461 | return ret; | 459 | return ret; |
462 | } | 460 | } |
@@ -486,7 +484,7 @@ static long media_device_enum_links32(struct media_device *mdev, | |||
486 | links.pads = compat_ptr(pads_ptr); | 484 | links.pads = compat_ptr(pads_ptr); |
487 | links.links = compat_ptr(links_ptr); | 485 | links.links = compat_ptr(links_ptr); |
488 | 486 | ||
489 | return __media_device_enum_links(mdev, &links); | 487 | return media_device_enum_links(mdev, &links); |
490 | } | 488 | } |
491 | 489 | ||
492 | #define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32) | 490 | #define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32) |
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index d8a2299f0c2a..c68239e60487 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c | |||
@@ -65,6 +65,8 @@ static inline const char *intf_type(struct media_interface *intf) | |||
65 | return "v4l-subdev"; | 65 | return "v4l-subdev"; |
66 | case MEDIA_INTF_T_V4L_SWRADIO: | 66 | case MEDIA_INTF_T_V4L_SWRADIO: |
67 | return "v4l-swradio"; | 67 | return "v4l-swradio"; |
68 | case MEDIA_INTF_T_V4L_TOUCH: | ||
69 | return "v4l-touch"; | ||
68 | case MEDIA_INTF_T_ALSA_PCM_CAPTURE: | 70 | case MEDIA_INTF_T_ALSA_PCM_CAPTURE: |
69 | return "alsa-pcm-capture"; | 71 | return "alsa-pcm-capture"; |
70 | case MEDIA_INTF_T_ALSA_PCM_PLAYBACK: | 72 | case MEDIA_INTF_T_ALSA_PCM_PLAYBACK: |
@@ -806,17 +808,18 @@ int __media_entity_setup_link(struct media_link *link, u32 flags) | |||
806 | 808 | ||
807 | mdev = source->graph_obj.mdev; | 809 | mdev = source->graph_obj.mdev; |
808 | 810 | ||
809 | if (mdev->link_notify) { | 811 | if (mdev->ops && mdev->ops->link_notify) { |
810 | ret = mdev->link_notify(link, flags, | 812 | ret = mdev->ops->link_notify(link, flags, |
811 | MEDIA_DEV_NOTIFY_PRE_LINK_CH); | 813 | MEDIA_DEV_NOTIFY_PRE_LINK_CH); |
812 | if (ret < 0) | 814 | if (ret < 0) |
813 | return ret; | 815 | return ret; |
814 | } | 816 | } |
815 | 817 | ||
816 | ret = __media_entity_setup_link_notify(link, flags); | 818 | ret = __media_entity_setup_link_notify(link, flags); |
817 | 819 | ||
818 | if (mdev->link_notify) | 820 | if (mdev->ops && mdev->ops->link_notify) |
819 | mdev->link_notify(link, flags, MEDIA_DEV_NOTIFY_POST_LINK_CH); | 821 | mdev->ops->link_notify(link, flags, |
822 | MEDIA_DEV_NOTIFY_POST_LINK_CH); | ||
820 | 823 | ||
821 | return ret; | 824 | return ret; |
822 | } | 825 | } |
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 4f6467fbaeb4..da28e68c87d8 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig | |||
@@ -13,6 +13,7 @@ if MEDIA_CAMERA_SUPPORT | |||
13 | source "drivers/media/pci/meye/Kconfig" | 13 | source "drivers/media/pci/meye/Kconfig" |
14 | source "drivers/media/pci/solo6x10/Kconfig" | 14 | source "drivers/media/pci/solo6x10/Kconfig" |
15 | source "drivers/media/pci/sta2x11/Kconfig" | 15 | source "drivers/media/pci/sta2x11/Kconfig" |
16 | source "drivers/media/pci/tw5864/Kconfig" | ||
16 | source "drivers/media/pci/tw68/Kconfig" | 17 | source "drivers/media/pci/tw68/Kconfig" |
17 | source "drivers/media/pci/tw686x/Kconfig" | 18 | source "drivers/media/pci/tw686x/Kconfig" |
18 | source "drivers/media/pci/zoran/Kconfig" | 19 | source "drivers/media/pci/zoran/Kconfig" |
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index 2e54c36441f7..a7e8af0f64a7 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile | |||
@@ -31,3 +31,4 @@ obj-$(CONFIG_VIDEO_MEYE) += meye/ | |||
31 | obj-$(CONFIG_STA2X11_VIP) += sta2x11/ | 31 | obj-$(CONFIG_STA2X11_VIP) += sta2x11/ |
32 | obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ | 32 | obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ |
33 | obj-$(CONFIG_VIDEO_COBALT) += cobalt/ | 33 | obj-$(CONFIG_VIDEO_COBALT) += cobalt/ |
34 | obj-$(CONFIG_VIDEO_TW5864) += tw5864/ | ||
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index df54e17ef864..97b91a9f9fa9 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c | |||
@@ -2804,30 +2804,44 @@ static int bttv_cropcap(struct file *file, void *priv, | |||
2804 | cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | 2804 | cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) |
2805 | return -EINVAL; | 2805 | return -EINVAL; |
2806 | 2806 | ||
2807 | *cap = bttv_tvnorms[btv->tvnorm].cropcap; | 2807 | /* defrect and bounds are set via g_selection */ |
2808 | cap->pixelaspect = bttv_tvnorms[btv->tvnorm].cropcap.pixelaspect; | ||
2808 | 2809 | ||
2809 | return 0; | 2810 | return 0; |
2810 | } | 2811 | } |
2811 | 2812 | ||
2812 | static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop) | 2813 | static int bttv_g_selection(struct file *file, void *f, struct v4l2_selection *sel) |
2813 | { | 2814 | { |
2814 | struct bttv_fh *fh = f; | 2815 | struct bttv_fh *fh = f; |
2815 | struct bttv *btv = fh->btv; | 2816 | struct bttv *btv = fh->btv; |
2816 | 2817 | ||
2817 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | 2818 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
2818 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | 2819 | sel->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) |
2819 | return -EINVAL; | 2820 | return -EINVAL; |
2820 | 2821 | ||
2821 | /* No fh->do_crop = 1; because btv->crop[1] may be | 2822 | switch (sel->target) { |
2822 | inconsistent with fh->width or fh->height and apps | 2823 | case V4L2_SEL_TGT_CROP: |
2823 | do not expect a change here. */ | 2824 | /* |
2824 | 2825 | * No fh->do_crop = 1; because btv->crop[1] may be | |
2825 | crop->c = btv->crop[!!fh->do_crop].rect; | 2826 | * inconsistent with fh->width or fh->height and apps |
2827 | * do not expect a change here. | ||
2828 | */ | ||
2829 | sel->r = btv->crop[!!fh->do_crop].rect; | ||
2830 | break; | ||
2831 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
2832 | sel->r = bttv_tvnorms[btv->tvnorm].cropcap.defrect; | ||
2833 | break; | ||
2834 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
2835 | sel->r = bttv_tvnorms[btv->tvnorm].cropcap.bounds; | ||
2836 | break; | ||
2837 | default: | ||
2838 | return -EINVAL; | ||
2839 | } | ||
2826 | 2840 | ||
2827 | return 0; | 2841 | return 0; |
2828 | } | 2842 | } |
2829 | 2843 | ||
2830 | static int bttv_s_crop(struct file *file, void *f, const struct v4l2_crop *crop) | 2844 | static int bttv_s_selection(struct file *file, void *f, struct v4l2_selection *sel) |
2831 | { | 2845 | { |
2832 | struct bttv_fh *fh = f; | 2846 | struct bttv_fh *fh = f; |
2833 | struct bttv *btv = fh->btv; | 2847 | struct bttv *btv = fh->btv; |
@@ -2839,8 +2853,11 @@ static int bttv_s_crop(struct file *file, void *f, const struct v4l2_crop *crop) | |||
2839 | __s32 b_right; | 2853 | __s32 b_right; |
2840 | __s32 b_bottom; | 2854 | __s32 b_bottom; |
2841 | 2855 | ||
2842 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | 2856 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
2843 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | 2857 | sel->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) |
2858 | return -EINVAL; | ||
2859 | |||
2860 | if (sel->target != V4L2_SEL_TGT_CROP) | ||
2844 | return -EINVAL; | 2861 | return -EINVAL; |
2845 | 2862 | ||
2846 | /* Make sure tvnorm, vbi_end and the current cropping | 2863 | /* Make sure tvnorm, vbi_end and the current cropping |
@@ -2864,22 +2881,24 @@ static int bttv_s_crop(struct file *file, void *f, const struct v4l2_crop *crop) | |||
2864 | } | 2881 | } |
2865 | 2882 | ||
2866 | /* Min. scaled size 48 x 32. */ | 2883 | /* Min. scaled size 48 x 32. */ |
2867 | c.rect.left = clamp_t(s32, crop->c.left, b_left, b_right - 48); | 2884 | c.rect.left = clamp_t(s32, sel->r.left, b_left, b_right - 48); |
2868 | c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); | 2885 | c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); |
2869 | 2886 | ||
2870 | c.rect.width = clamp_t(s32, crop->c.width, | 2887 | c.rect.width = clamp_t(s32, sel->r.width, |
2871 | 48, b_right - c.rect.left); | 2888 | 48, b_right - c.rect.left); |
2872 | 2889 | ||
2873 | c.rect.top = clamp_t(s32, crop->c.top, b_top, b_bottom - 32); | 2890 | c.rect.top = clamp_t(s32, sel->r.top, b_top, b_bottom - 32); |
2874 | /* Top and height must be a multiple of two. */ | 2891 | /* Top and height must be a multiple of two. */ |
2875 | c.rect.top = (c.rect.top + 1) & ~1; | 2892 | c.rect.top = (c.rect.top + 1) & ~1; |
2876 | 2893 | ||
2877 | c.rect.height = clamp_t(s32, crop->c.height, | 2894 | c.rect.height = clamp_t(s32, sel->r.height, |
2878 | 32, b_bottom - c.rect.top); | 2895 | 32, b_bottom - c.rect.top); |
2879 | c.rect.height = (c.rect.height + 1) & ~1; | 2896 | c.rect.height = (c.rect.height + 1) & ~1; |
2880 | 2897 | ||
2881 | bttv_crop_calc_limits(&c); | 2898 | bttv_crop_calc_limits(&c); |
2882 | 2899 | ||
2900 | sel->r = c.rect; | ||
2901 | |||
2883 | btv->crop[1] = c; | 2902 | btv->crop[1] = c; |
2884 | 2903 | ||
2885 | fh->do_crop = 1; | 2904 | fh->do_crop = 1; |
@@ -3047,10 +3066,10 @@ static int bttv_open(struct file *file) | |||
3047 | which only change on request. These are stored in btv->crop[1]. | 3066 | which only change on request. These are stored in btv->crop[1]. |
3048 | However for compatibility with V4L apps and cropping unaware | 3067 | However for compatibility with V4L apps and cropping unaware |
3049 | V4L2 apps we now reset the cropping parameters as seen through | 3068 | V4L2 apps we now reset the cropping parameters as seen through |
3050 | this fh, which is to say VIDIOC_G_CROP and scaling limit checks | 3069 | this fh, which is to say VIDIOC_G_SELECTION and scaling limit checks |
3051 | will use btv->crop[0], the default cropping parameters for the | 3070 | will use btv->crop[0], the default cropping parameters for the |
3052 | current video standard, and VIDIOC_S_FMT will not implicitely | 3071 | current video standard, and VIDIOC_S_FMT will not implicitely |
3053 | change the cropping parameters until VIDIOC_S_CROP has been | 3072 | change the cropping parameters until VIDIOC_S_SELECTION has been |
3054 | called. */ | 3073 | called. */ |
3055 | fh->do_crop = !reset_crop; /* module parameter */ | 3074 | fh->do_crop = !reset_crop; /* module parameter */ |
3056 | 3075 | ||
@@ -3159,8 +3178,8 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = { | |||
3159 | .vidioc_streamoff = bttv_streamoff, | 3178 | .vidioc_streamoff = bttv_streamoff, |
3160 | .vidioc_g_tuner = bttv_g_tuner, | 3179 | .vidioc_g_tuner = bttv_g_tuner, |
3161 | .vidioc_s_tuner = bttv_s_tuner, | 3180 | .vidioc_s_tuner = bttv_s_tuner, |
3162 | .vidioc_g_crop = bttv_g_crop, | 3181 | .vidioc_g_selection = bttv_g_selection, |
3163 | .vidioc_s_crop = bttv_s_crop, | 3182 | .vidioc_s_selection = bttv_s_selection, |
3164 | .vidioc_g_fbuf = bttv_g_fbuf, | 3183 | .vidioc_g_fbuf = bttv_g_fbuf, |
3165 | .vidioc_s_fbuf = bttv_s_fbuf, | 3184 | .vidioc_s_fbuf = bttv_s_fbuf, |
3166 | .vidioc_overlay = bttv_overlay, | 3185 | .vidioc_overlay = bttv_overlay, |
diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index b1e0023f923c..9efc4559fa8e 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h | |||
@@ -232,7 +232,7 @@ struct bttv_fh { | |||
232 | const struct bttv_format *ovfmt; | 232 | const struct bttv_format *ovfmt; |
233 | struct bttv_overlay ov; | 233 | struct bttv_overlay ov; |
234 | 234 | ||
235 | /* Application called VIDIOC_S_CROP. */ | 235 | /* Application called VIDIOC_S_SELECTION. */ |
236 | int do_crop; | 236 | int do_crop; |
237 | 237 | ||
238 | /* vbi capture */ | 238 | /* vbi capture */ |
diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c index f0bdf10cfd57..49013c6b8646 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c +++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c | |||
@@ -510,7 +510,7 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, | |||
510 | return vmalloc_to_page(pageptr); | 510 | return vmalloc_to_page(pageptr); |
511 | } | 511 | } |
512 | 512 | ||
513 | static struct snd_pcm_ops snd_cobalt_pcm_capture_ops = { | 513 | static const struct snd_pcm_ops snd_cobalt_pcm_capture_ops = { |
514 | .open = snd_cobalt_pcm_capture_open, | 514 | .open = snd_cobalt_pcm_capture_open, |
515 | .close = snd_cobalt_pcm_capture_close, | 515 | .close = snd_cobalt_pcm_capture_close, |
516 | .ioctl = snd_cobalt_pcm_ioctl, | 516 | .ioctl = snd_cobalt_pcm_ioctl, |
@@ -522,7 +522,7 @@ static struct snd_pcm_ops snd_cobalt_pcm_capture_ops = { | |||
522 | .page = snd_pcm_get_vmalloc_page, | 522 | .page = snd_pcm_get_vmalloc_page, |
523 | }; | 523 | }; |
524 | 524 | ||
525 | static struct snd_pcm_ops snd_cobalt_pcm_playback_ops = { | 525 | static const struct snd_pcm_ops snd_cobalt_pcm_playback_ops = { |
526 | .open = snd_cobalt_pcm_playback_open, | 526 | .open = snd_cobalt_pcm_playback_open, |
527 | .close = snd_cobalt_pcm_playback_close, | 527 | .close = snd_cobalt_pcm_playback_close, |
528 | .ioctl = snd_cobalt_pcm_ioctl, | 528 | .ioctl = snd_cobalt_pcm_ioctl, |
diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 476f7f0dcf81..979634000597 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c | |||
@@ -60,30 +60,31 @@ MODULE_DESCRIPTION("cobalt driver"); | |||
60 | MODULE_LICENSE("GPL"); | 60 | MODULE_LICENSE("GPL"); |
61 | 61 | ||
62 | static u8 edid[256] = { | 62 | static u8 edid[256] = { |
63 | 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, | 63 | 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, |
64 | 0x50, 0x21, 0x9C, 0x27, 0x00, 0x00, 0x00, 0x00, | 64 | 0x50, 0x21, 0x32, 0x27, 0x00, 0x00, 0x00, 0x00, |
65 | 0x19, 0x12, 0x01, 0x03, 0x80, 0x00, 0x00, 0x78, | 65 | 0x22, 0x1a, 0x01, 0x03, 0x80, 0x30, 0x1b, 0x78, |
66 | 0x0E, 0x00, 0xB2, 0xA0, 0x57, 0x49, 0x9B, 0x26, | 66 | 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, |
67 | 0x10, 0x48, 0x4F, 0x2F, 0xCF, 0x00, 0x31, 0x59, | 67 | 0x0f, 0x50, 0x54, 0x2f, 0xcf, 0x00, 0x31, 0x59, |
68 | 0x45, 0x59, 0x61, 0x59, 0x81, 0x99, 0x01, 0x01, | 68 | 0x45, 0x59, 0x61, 0x59, 0x81, 0x99, 0x01, 0x01, |
69 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A, | 69 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, |
70 | 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, | 70 | 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, |
71 | 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, | 71 | 0x46, 0x00, 0xe0, 0x0e, 0x11, 0x00, 0x00, 0x1e, |
72 | 0x00, 0x00, 0x00, 0xFD, 0x00, 0x31, 0x55, 0x18, | 72 | 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18, |
73 | 0x5E, 0x11, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, | 73 | 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, |
74 | 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x43, | 74 | 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x63, |
75 | 0x20, 0x39, 0x30, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, | 75 | 0x6f, 0x62, 0x61, 0x6c, 0x74, 0x0a, 0x20, 0x20, |
76 | 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x10, | 76 | 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x10, |
77 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
78 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x9c, | ||
79 | |||
80 | 0x02, 0x03, 0x1f, 0xf0, 0x4a, 0x90, 0x1f, 0x04, | ||
81 | 0x13, 0x22, 0x21, 0x20, 0x02, 0x11, 0x01, 0x23, | ||
82 | 0x09, 0x07, 0x07, 0x68, 0x03, 0x0c, 0x00, 0x10, | ||
83 | 0x00, 0x00, 0x22, 0x0f, 0xe2, 0x00, 0xea, 0x00, | ||
84 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
85 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
77 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
78 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, | ||
79 | 0x02, 0x03, 0x1a, 0xc0, 0x48, 0xa2, 0x10, 0x04, | ||
80 | 0x02, 0x01, 0x21, 0x14, 0x13, 0x23, 0x09, 0x07, | ||
81 | 0x07, 0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, 0xe2, | ||
82 | 0x00, 0x2a, 0x01, 0x1d, 0x00, 0x80, 0x51, 0xd0, | ||
83 | 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0x00, 0x00, | ||
84 | 0x00, 0x00, 0x00, 0x1e, 0x8c, 0x0a, 0xd0, 0x8a, | ||
85 | 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, | ||
86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, | ||
87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
@@ -91,7 +92,7 @@ static u8 edid[256] = { | |||
91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7 | 95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, |
95 | }; | 96 | }; |
96 | 97 | ||
97 | static void cobalt_set_interrupt(struct cobalt *cobalt, bool enable) | 98 | static void cobalt_set_interrupt(struct cobalt *cobalt, bool enable) |
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index d05672fe9ff9..5c76637900d0 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c | |||
@@ -161,8 +161,11 @@ static void cobalt_enable_output(struct cobalt_stream *s) | |||
161 | struct v4l2_subdev_format sd_fmt = { | 161 | struct v4l2_subdev_format sd_fmt = { |
162 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | 162 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
163 | }; | 163 | }; |
164 | u64 clk = bt->pixelclock; | ||
164 | 165 | ||
165 | if (!cobalt_cpld_set_freq(cobalt, bt->pixelclock)) { | 166 | if (bt->flags & V4L2_DV_FL_REDUCED_FPS) |
167 | clk = div_u64(clk * 1000ULL, 1001); | ||
168 | if (!cobalt_cpld_set_freq(cobalt, clk)) { | ||
166 | cobalt_err("pixelclock out of range\n"); | 169 | cobalt_err("pixelclock out of range\n"); |
167 | return; | 170 | return; |
168 | } | 171 | } |
@@ -644,7 +647,7 @@ static int cobalt_s_dv_timings(struct file *file, void *priv_fh, | |||
644 | return 0; | 647 | return 0; |
645 | } | 648 | } |
646 | 649 | ||
647 | if (v4l2_match_dv_timings(timings, &s->timings, 0, false)) | 650 | if (v4l2_match_dv_timings(timings, &s->timings, 0, true)) |
648 | return 0; | 651 | return 0; |
649 | 652 | ||
650 | if (vb2_is_busy(&s->q)) | 653 | if (vb2_is_busy(&s->q)) |
diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.c b/drivers/media/pci/cx18/cx18-alsa-pcm.c index ffb6acdc575f..5344510fbea3 100644 --- a/drivers/media/pci/cx18/cx18-alsa-pcm.c +++ b/drivers/media/pci/cx18/cx18-alsa-pcm.c | |||
@@ -311,7 +311,7 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, | |||
311 | return vmalloc_to_page(pageptr); | 311 | return vmalloc_to_page(pageptr); |
312 | } | 312 | } |
313 | 313 | ||
314 | static struct snd_pcm_ops snd_cx18_pcm_capture_ops = { | 314 | static const struct snd_pcm_ops snd_cx18_pcm_capture_ops = { |
315 | .open = snd_cx18_pcm_capture_open, | 315 | .open = snd_cx18_pcm_capture_open, |
316 | .close = snd_cx18_pcm_capture_close, | 316 | .close = snd_cx18_pcm_capture_close, |
317 | .ioctl = snd_cx18_pcm_ioctl, | 317 | .ioctl = snd_cx18_pcm_ioctl, |
diff --git a/drivers/media/pci/cx18/cx18-i2c.c b/drivers/media/pci/cx18/cx18-i2c.c index 4af8cd6df95d..c9329371a3f8 100644 --- a/drivers/media/pci/cx18/cx18-i2c.c +++ b/drivers/media/pci/cx18/cx18-i2c.c | |||
@@ -98,7 +98,8 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw, | |||
98 | case CX18_HW_Z8F0811_IR_RX_HAUP: | 98 | case CX18_HW_Z8F0811_IR_RX_HAUP: |
99 | init_data->ir_codes = RC_MAP_HAUPPAUGE; | 99 | init_data->ir_codes = RC_MAP_HAUPPAUGE; |
100 | init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; | 100 | init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; |
101 | init_data->type = RC_BIT_RC5; | 101 | init_data->type = RC_BIT_RC5 | RC_BIT_RC6_MCE | |
102 | RC_BIT_RC6_6A_32; | ||
102 | init_data->name = cx->card_name; | 103 | init_data->name = cx->card_name; |
103 | info.platform_data = init_data; | 104 | info.platform_data = init_data; |
104 | break; | 105 | break; |
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 4d080da7afaf..da892f3e3c29 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c | |||
@@ -1223,7 +1223,7 @@ static void cx23885_stop_streaming(struct vb2_queue *q) | |||
1223 | cx23885_cancel_buffers(&dev->ts1); | 1223 | cx23885_cancel_buffers(&dev->ts1); |
1224 | } | 1224 | } |
1225 | 1225 | ||
1226 | static struct vb2_ops cx23885_qops = { | 1226 | static const struct vb2_ops cx23885_qops = { |
1227 | .queue_setup = queue_setup, | 1227 | .queue_setup = queue_setup, |
1228 | .buf_prepare = buffer_prepare, | 1228 | .buf_prepare = buffer_prepare, |
1229 | .buf_finish = buffer_finish, | 1229 | .buf_finish = buffer_finish, |
diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index ae7c2e89ad1c..6115d4e148ba 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c | |||
@@ -506,7 +506,7 @@ static struct page *snd_cx23885_page(struct snd_pcm_substream *substream, | |||
506 | /* | 506 | /* |
507 | * operators | 507 | * operators |
508 | */ | 508 | */ |
509 | static struct snd_pcm_ops snd_cx23885_pcm_ops = { | 509 | static const struct snd_pcm_ops snd_cx23885_pcm_ops = { |
510 | .open = snd_cx23885_pcm_open, | 510 | .open = snd_cx23885_pcm_open, |
511 | .close = snd_cx23885_close, | 511 | .close = snd_cx23885_close, |
512 | .ioctl = snd_pcm_lib_ioctl, | 512 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 4abf50f2694f..99ba8d6328f0 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c | |||
@@ -770,6 +770,11 @@ struct cx23885_board cx23885_boards[] = { | |||
770 | .portb = CX23885_MPEG_DVB, | 770 | .portb = CX23885_MPEG_DVB, |
771 | .portc = CX23885_MPEG_DVB, | 771 | .portc = CX23885_MPEG_DVB, |
772 | }, | 772 | }, |
773 | [CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC] = { | ||
774 | .name = "Hauppauge WinTV-QuadHD-ATSC", | ||
775 | .portb = CX23885_MPEG_DVB, | ||
776 | .portc = CX23885_MPEG_DVB, | ||
777 | }, | ||
773 | }; | 778 | }; |
774 | const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); | 779 | const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); |
775 | 780 | ||
@@ -1073,6 +1078,14 @@ struct cx23885_subid cx23885_subids[] = { | |||
1073 | .subvendor = 0x0070, | 1078 | .subvendor = 0x0070, |
1074 | .subdevice = 0x6b28, | 1079 | .subdevice = 0x6b28, |
1075 | .card = CX23885_BOARD_HAUPPAUGE_QUADHD_DVB, /* Tuner Pair 2 */ | 1080 | .card = CX23885_BOARD_HAUPPAUGE_QUADHD_DVB, /* Tuner Pair 2 */ |
1081 | }, { | ||
1082 | .subvendor = 0x0070, | ||
1083 | .subdevice = 0x6a18, | ||
1084 | .card = CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC, /* Tuner Pair 1 */ | ||
1085 | }, { | ||
1086 | .subvendor = 0x0070, | ||
1087 | .subdevice = 0x6b18, | ||
1088 | .card = CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC, /* Tuner Pair 2 */ | ||
1076 | }, | 1089 | }, |
1077 | }; | 1090 | }; |
1078 | const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); | 1091 | const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); |
@@ -1278,6 +1291,18 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) | |||
1278 | /* WinTV-QuadHD (DVB) Tuner Pair 2 (PCIe, IR, half height, | 1291 | /* WinTV-QuadHD (DVB) Tuner Pair 2 (PCIe, IR, half height, |
1279 | DVB-T/T2/C, DVB-T/T2/C */ | 1292 | DVB-T/T2/C, DVB-T/T2/C */ |
1280 | break; | 1293 | break; |
1294 | case 165100: | ||
1295 | /* | ||
1296 | * WinTV-QuadHD (ATSC) Tuner Pair 1 (PCIe, IR, half height, | ||
1297 | * ATSC, ATSC | ||
1298 | */ | ||
1299 | break; | ||
1300 | case 165101: | ||
1301 | /* | ||
1302 | * WinTV-QuadHD (DVB) Tuner Pair 2 (PCIe, IR, half height, | ||
1303 | * ATSC, ATSC | ||
1304 | */ | ||
1305 | break; | ||
1281 | default: | 1306 | default: |
1282 | printk(KERN_WARNING "%s: warning: " | 1307 | printk(KERN_WARNING "%s: warning: " |
1283 | "unknown hauppauge model #%d\n", | 1308 | "unknown hauppauge model #%d\n", |
@@ -1751,6 +1776,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) | |||
1751 | break; | 1776 | break; |
1752 | case CX23885_BOARD_HAUPPAUGE_HVR5525: | 1777 | case CX23885_BOARD_HAUPPAUGE_HVR5525: |
1753 | case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: | 1778 | case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: |
1779 | case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: | ||
1754 | /* | 1780 | /* |
1755 | * HVR5525 GPIO Details: | 1781 | * HVR5525 GPIO Details: |
1756 | * GPIO-00 IR_WIDE | 1782 | * GPIO-00 IR_WIDE |
@@ -1826,6 +1852,7 @@ int cx23885_ir_init(struct cx23885_dev *dev) | |||
1826 | case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: | 1852 | case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: |
1827 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | 1853 | case CX23885_BOARD_HAUPPAUGE_HVR1210: |
1828 | case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: | 1854 | case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: |
1855 | case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: | ||
1829 | /* FIXME: Implement me */ | 1856 | /* FIXME: Implement me */ |
1830 | break; | 1857 | break; |
1831 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | 1858 | case CX23885_BOARD_HAUPPAUGE_HVR1270: |
@@ -2025,6 +2052,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) | |||
2025 | case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE: | 2052 | case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE: |
2026 | case CX23885_BOARD_HAUPPAUGE_HVR5525: | 2053 | case CX23885_BOARD_HAUPPAUGE_HVR5525: |
2027 | case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: | 2054 | case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: |
2055 | case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: | ||
2028 | if (dev->i2c_bus[0].i2c_rc == 0) | 2056 | if (dev->i2c_bus[0].i2c_rc == 0) |
2029 | hauppauge_eeprom(dev, eeprom+0xc0); | 2057 | hauppauge_eeprom(dev, eeprom+0xc0); |
2030 | break; | 2058 | break; |
@@ -2171,6 +2199,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) | |||
2171 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | 2199 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; |
2172 | break; | 2200 | break; |
2173 | case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: | 2201 | case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: |
2202 | case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: | ||
2174 | ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | 2203 | ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ |
2175 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | 2204 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ |
2176 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | 2205 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; |
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index e5748a93c479..818f3c2fc98d 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c | |||
@@ -74,6 +74,7 @@ | |||
74 | #include "sp2.h" | 74 | #include "sp2.h" |
75 | #include "m88ds3103.h" | 75 | #include "m88ds3103.h" |
76 | #include "m88rs6000t.h" | 76 | #include "m88rs6000t.h" |
77 | #include "lgdt3306a.h" | ||
77 | 78 | ||
78 | static unsigned int debug; | 79 | static unsigned int debug; |
79 | 80 | ||
@@ -172,7 +173,7 @@ static void cx23885_stop_streaming(struct vb2_queue *q) | |||
172 | cx23885_cancel_buffers(port); | 173 | cx23885_cancel_buffers(port); |
173 | } | 174 | } |
174 | 175 | ||
175 | static struct vb2_ops dvb_qops = { | 176 | static const struct vb2_ops dvb_qops = { |
176 | .queue_setup = queue_setup, | 177 | .queue_setup = queue_setup, |
177 | .buf_prepare = buffer_prepare, | 178 | .buf_prepare = buffer_prepare, |
178 | .buf_finish = buffer_finish, | 179 | .buf_finish = buffer_finish, |
@@ -574,6 +575,30 @@ static struct stb6100_config prof_8000_stb6100_config = { | |||
574 | .refclock = 27000000, | 575 | .refclock = 27000000, |
575 | }; | 576 | }; |
576 | 577 | ||
578 | static struct lgdt3306a_config hauppauge_quadHD_ATSC_a_config = { | ||
579 | .i2c_addr = 0x59, | ||
580 | .qam_if_khz = 4000, | ||
581 | .vsb_if_khz = 3250, | ||
582 | .deny_i2c_rptr = 1, /* Disabled */ | ||
583 | .spectral_inversion = 0, /* Disabled */ | ||
584 | .mpeg_mode = LGDT3306A_MPEG_SERIAL, | ||
585 | .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, | ||
586 | .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, | ||
587 | .xtalMHz = 25, /* 24 or 25 */ | ||
588 | }; | ||
589 | |||
590 | static struct lgdt3306a_config hauppauge_quadHD_ATSC_b_config = { | ||
591 | .i2c_addr = 0x0e, | ||
592 | .qam_if_khz = 4000, | ||
593 | .vsb_if_khz = 3250, | ||
594 | .deny_i2c_rptr = 1, /* Disabled */ | ||
595 | .spectral_inversion = 0, /* Disabled */ | ||
596 | .mpeg_mode = LGDT3306A_MPEG_SERIAL, | ||
597 | .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, | ||
598 | .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, | ||
599 | .xtalMHz = 25, /* 24 or 25 */ | ||
600 | }; | ||
601 | |||
577 | static int p8000_set_voltage(struct dvb_frontend *fe, | 602 | static int p8000_set_voltage(struct dvb_frontend *fe, |
578 | enum fe_sec_voltage voltage) | 603 | enum fe_sec_voltage voltage) |
579 | { | 604 | { |
@@ -867,12 +892,6 @@ static const struct tda10071_platform_data hauppauge_tda10071_pdata = { | |||
867 | .tuner_i2c_addr = 0x54, | 892 | .tuner_i2c_addr = 0x54, |
868 | }; | 893 | }; |
869 | 894 | ||
870 | static const struct si2165_config hauppauge_hvr4400_si2165_config = { | ||
871 | .i2c_addr = 0x64, | ||
872 | .chip_mode = SI2165_MODE_PLL_XTAL, | ||
873 | .ref_freq_Hz = 16000000, | ||
874 | }; | ||
875 | |||
876 | static const struct m88ds3103_config dvbsky_t9580_m88ds3103_config = { | 895 | static const struct m88ds3103_config dvbsky_t9580_m88ds3103_config = { |
877 | .i2c_addr = 0x68, | 896 | .i2c_addr = 0x68, |
878 | .clock = 27000000, | 897 | .clock = 27000000, |
@@ -1182,6 +1201,7 @@ static int dvb_register(struct cx23885_tsport *port) | |||
1182 | struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; | 1201 | struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; |
1183 | struct vb2_dvb_frontend *fe0, *fe1 = NULL; | 1202 | struct vb2_dvb_frontend *fe0, *fe1 = NULL; |
1184 | struct si2168_config si2168_config; | 1203 | struct si2168_config si2168_config; |
1204 | struct si2165_platform_data si2165_pdata; | ||
1185 | struct si2157_config si2157_config; | 1205 | struct si2157_config si2157_config; |
1186 | struct ts2020_config ts2020_config; | 1206 | struct ts2020_config ts2020_config; |
1187 | struct i2c_board_info info; | 1207 | struct i2c_board_info info; |
@@ -1700,6 +1720,9 @@ static int dvb_register(struct cx23885_tsport *port) | |||
1700 | } | 1720 | } |
1701 | break; | 1721 | break; |
1702 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | 1722 | case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: |
1723 | if (port->nr > 2) | ||
1724 | return 0; | ||
1725 | |||
1703 | i2c_bus = &dev->i2c_bus[0]; | 1726 | i2c_bus = &dev->i2c_bus[0]; |
1704 | mfe_shared = 1;/* MFE */ | 1727 | mfe_shared = 1;/* MFE */ |
1705 | port->frontends.gate = 0;/* not clear for me yet */ | 1728 | port->frontends.gate = 0;/* not clear for me yet */ |
@@ -1839,9 +1862,26 @@ static int dvb_register(struct cx23885_tsport *port) | |||
1839 | break; | 1862 | break; |
1840 | /* port c */ | 1863 | /* port c */ |
1841 | case 2: | 1864 | case 2: |
1842 | fe0->dvb.frontend = dvb_attach(si2165_attach, | 1865 | /* attach frontend */ |
1843 | &hauppauge_hvr4400_si2165_config, | 1866 | memset(&si2165_pdata, 0, sizeof(si2165_pdata)); |
1844 | &i2c_bus->i2c_adap); | 1867 | si2165_pdata.fe = &fe0->dvb.frontend; |
1868 | si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL, | ||
1869 | si2165_pdata.ref_freq_Hz = 16000000, | ||
1870 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1871 | strlcpy(info.type, "si2165", I2C_NAME_SIZE); | ||
1872 | info.addr = 0x64; | ||
1873 | info.platform_data = &si2165_pdata; | ||
1874 | request_module(info.type); | ||
1875 | client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); | ||
1876 | if (client_demod == NULL || | ||
1877 | client_demod->dev.driver == NULL) | ||
1878 | goto frontend_detach; | ||
1879 | if (!try_module_get(client_demod->dev.driver->owner)) { | ||
1880 | i2c_unregister_device(client_demod); | ||
1881 | goto frontend_detach; | ||
1882 | } | ||
1883 | port->i2c_client_demod = client_demod; | ||
1884 | |||
1845 | if (fe0->dvb.frontend == NULL) | 1885 | if (fe0->dvb.frontend == NULL) |
1846 | break; | 1886 | break; |
1847 | fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; | 1887 | fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; |
@@ -2365,6 +2405,81 @@ static int dvb_register(struct cx23885_tsport *port) | |||
2365 | break; | 2405 | break; |
2366 | } | 2406 | } |
2367 | break; | 2407 | break; |
2408 | case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC: | ||
2409 | switch (port->nr) { | ||
2410 | /* port b - Terrestrial/cable */ | ||
2411 | case 1: | ||
2412 | /* attach frontend */ | ||
2413 | i2c_bus = &dev->i2c_bus[0]; | ||
2414 | fe0->dvb.frontend = dvb_attach(lgdt3306a_attach, | ||
2415 | &hauppauge_quadHD_ATSC_a_config, &i2c_bus->i2c_adap); | ||
2416 | if (fe0->dvb.frontend == NULL) | ||
2417 | break; | ||
2418 | |||
2419 | /* attach tuner */ | ||
2420 | memset(&si2157_config, 0, sizeof(si2157_config)); | ||
2421 | si2157_config.fe = fe0->dvb.frontend; | ||
2422 | si2157_config.if_port = 1; | ||
2423 | si2157_config.inversion = 1; | ||
2424 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
2425 | strlcpy(info.type, "si2157", I2C_NAME_SIZE); | ||
2426 | info.addr = 0x60; | ||
2427 | info.platform_data = &si2157_config; | ||
2428 | request_module("%s", info.type); | ||
2429 | client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info); | ||
2430 | if (!client_tuner || !client_tuner->dev.driver) { | ||
2431 | module_put(client_demod->dev.driver->owner); | ||
2432 | i2c_unregister_device(client_demod); | ||
2433 | port->i2c_client_demod = NULL; | ||
2434 | goto frontend_detach; | ||
2435 | } | ||
2436 | if (!try_module_get(client_tuner->dev.driver->owner)) { | ||
2437 | i2c_unregister_device(client_tuner); | ||
2438 | module_put(client_demod->dev.driver->owner); | ||
2439 | i2c_unregister_device(client_demod); | ||
2440 | port->i2c_client_demod = NULL; | ||
2441 | goto frontend_detach; | ||
2442 | } | ||
2443 | port->i2c_client_tuner = client_tuner; | ||
2444 | break; | ||
2445 | |||
2446 | /* port c - terrestrial/cable */ | ||
2447 | case 2: | ||
2448 | /* attach frontend */ | ||
2449 | i2c_bus = &dev->i2c_bus[0]; | ||
2450 | fe0->dvb.frontend = dvb_attach(lgdt3306a_attach, | ||
2451 | &hauppauge_quadHD_ATSC_b_config, &i2c_bus->i2c_adap); | ||
2452 | if (fe0->dvb.frontend == NULL) | ||
2453 | break; | ||
2454 | |||
2455 | /* attach tuner */ | ||
2456 | memset(&si2157_config, 0, sizeof(si2157_config)); | ||
2457 | si2157_config.fe = fe0->dvb.frontend; | ||
2458 | si2157_config.if_port = 1; | ||
2459 | si2157_config.inversion = 1; | ||
2460 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
2461 | strlcpy(info.type, "si2157", I2C_NAME_SIZE); | ||
2462 | info.addr = 0x62; | ||
2463 | info.platform_data = &si2157_config; | ||
2464 | request_module("%s", info.type); | ||
2465 | client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info); | ||
2466 | if (!client_tuner || !client_tuner->dev.driver) { | ||
2467 | module_put(client_demod->dev.driver->owner); | ||
2468 | i2c_unregister_device(client_demod); | ||
2469 | port->i2c_client_demod = NULL; | ||
2470 | goto frontend_detach; | ||
2471 | } | ||
2472 | if (!try_module_get(client_tuner->dev.driver->owner)) { | ||
2473 | i2c_unregister_device(client_tuner); | ||
2474 | module_put(client_demod->dev.driver->owner); | ||
2475 | i2c_unregister_device(client_demod); | ||
2476 | port->i2c_client_demod = NULL; | ||
2477 | goto frontend_detach; | ||
2478 | } | ||
2479 | port->i2c_client_tuner = client_tuner; | ||
2480 | break; | ||
2481 | } | ||
2482 | break; | ||
2368 | 2483 | ||
2369 | default: | 2484 | default: |
2370 | printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " | 2485 | printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " |
diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c index ae061b358591..61591225be9a 100644 --- a/drivers/media/pci/cx23885/cx23885-i2c.c +++ b/drivers/media/pci/cx23885/cx23885-i2c.c | |||
@@ -258,7 +258,7 @@ static u32 cx23885_functionality(struct i2c_adapter *adap) | |||
258 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; | 258 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; |
259 | } | 259 | } |
260 | 260 | ||
261 | static struct i2c_algorithm cx23885_i2c_algo_template = { | 261 | static const struct i2c_algorithm cx23885_i2c_algo_template = { |
262 | .master_xfer = i2c_xfer, | 262 | .master_xfer = i2c_xfer, |
263 | .functionality = cx23885_functionality, | 263 | .functionality = cx23885_functionality, |
264 | }; | 264 | }; |
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c index 64328d08ac2f..410c3141c163 100644 --- a/drivers/media/pci/cx23885/cx23885-input.c +++ b/drivers/media/pci/cx23885/cx23885-input.c | |||
@@ -293,7 +293,7 @@ int cx23885_input_init(struct cx23885_dev *dev) | |||
293 | case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | 293 | case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: |
294 | /* Integrated CX23885 IR controller */ | 294 | /* Integrated CX23885 IR controller */ |
295 | driver_type = RC_DRIVER_IR_RAW; | 295 | driver_type = RC_DRIVER_IR_RAW; |
296 | allowed_protos = RC_BIT_NEC; | 296 | allowed_protos = RC_BIT_ALL; |
297 | /* The grey Terratec remote with orange buttons */ | 297 | /* The grey Terratec remote with orange buttons */ |
298 | rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS; | 298 | rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS; |
299 | break; | 299 | break; |
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 6d735222a958..33d168ef278d 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c | |||
@@ -517,7 +517,7 @@ static void cx23885_stop_streaming(struct vb2_queue *q) | |||
517 | spin_unlock_irqrestore(&dev->slock, flags); | 517 | spin_unlock_irqrestore(&dev->slock, flags); |
518 | } | 518 | } |
519 | 519 | ||
520 | static struct vb2_ops cx23885_video_qops = { | 520 | static const struct vb2_ops cx23885_video_qops = { |
521 | .queue_setup = queue_setup, | 521 | .queue_setup = queue_setup, |
522 | .buf_prepare = buffer_prepare, | 522 | .buf_prepare = buffer_prepare, |
523 | .buf_finish = buffer_finish, | 523 | .buf_finish = buffer_finish, |
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 24a0a6c5b501..a6735afe2269 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h | |||
@@ -103,7 +103,8 @@ | |||
103 | #define CX23885_BOARD_HAUPPAUGE_STARBURST 53 | 103 | #define CX23885_BOARD_HAUPPAUGE_STARBURST 53 |
104 | #define CX23885_BOARD_VIEWCAST_260E 54 | 104 | #define CX23885_BOARD_VIEWCAST_260E 54 |
105 | #define CX23885_BOARD_VIEWCAST_460E 55 | 105 | #define CX23885_BOARD_VIEWCAST_460E 55 |
106 | #define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB 56 | 106 | #define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB 56 |
107 | #define CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC 57 | ||
107 | 108 | ||
108 | #define GPIO_0 0x00000001 | 109 | #define GPIO_0 0x00000001 |
109 | #define GPIO_1 0x00000002 | 110 | #define GPIO_1 0x00000002 |
@@ -256,7 +257,7 @@ struct cx23885_dmaqueue { | |||
256 | struct cx23885_tsport { | 257 | struct cx23885_tsport { |
257 | struct cx23885_dev *dev; | 258 | struct cx23885_dev *dev; |
258 | 259 | ||
259 | int nr; | 260 | unsigned nr; |
260 | int sram_chno; | 261 | int sram_chno; |
261 | 262 | ||
262 | struct vb2_dvb_frontends frontends; | 263 | struct vb2_dvb_frontends frontends; |
diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index df189b16af12..4711583de8fe 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c | |||
@@ -649,7 +649,7 @@ static struct page *snd_cx25821_page(struct snd_pcm_substream *substream, | |||
649 | /* | 649 | /* |
650 | * operators | 650 | * operators |
651 | */ | 651 | */ |
652 | static struct snd_pcm_ops snd_cx25821_pcm_ops = { | 652 | static const struct snd_pcm_ops snd_cx25821_pcm_ops = { |
653 | .open = snd_cx25821_pcm_open, | 653 | .open = snd_cx25821_pcm_open, |
654 | .close = snd_cx25821_close, | 654 | .close = snd_cx25821_close, |
655 | .ioctl = snd_pcm_lib_ioctl, | 655 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/drivers/media/pci/cx25821/cx25821-audio-upstream.c b/drivers/media/pci/cx25821/cx25821-audio-upstream.c index 68dbc2dbc982..7c8edb6181ec 100644 --- a/drivers/media/pci/cx25821/cx25821-audio-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-audio-upstream.c | |||
@@ -242,8 +242,7 @@ void cx25821_stop_upstream_audio(struct cx25821_dev *dev) | |||
242 | dev->_audioframe_count = 0; | 242 | dev->_audioframe_count = 0; |
243 | dev->_audiofile_status = END_OF_FILE; | 243 | dev->_audiofile_status = END_OF_FILE; |
244 | 244 | ||
245 | kfree(dev->_irq_audio_queues); | 245 | flush_work(&dev->_audio_work_entry); |
246 | dev->_irq_audio_queues = NULL; | ||
247 | 246 | ||
248 | kfree(dev->_audiofilename); | 247 | kfree(dev->_audiofilename); |
249 | } | 248 | } |
@@ -446,8 +445,7 @@ static int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num, | |||
446 | 445 | ||
447 | dev->_audioframe_index = dev->_last_index_irq; | 446 | dev->_audioframe_index = dev->_last_index_irq; |
448 | 447 | ||
449 | queue_work(dev->_irq_audio_queues, | 448 | schedule_work(&dev->_audio_work_entry); |
450 | &dev->_audio_work_entry); | ||
451 | } | 449 | } |
452 | 450 | ||
453 | if (dev->_is_first_audio_frame) { | 451 | if (dev->_is_first_audio_frame) { |
@@ -639,14 +637,6 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) | |||
639 | 637 | ||
640 | /* Work queue */ | 638 | /* Work queue */ |
641 | INIT_WORK(&dev->_audio_work_entry, cx25821_audioups_handler); | 639 | INIT_WORK(&dev->_audio_work_entry, cx25821_audioups_handler); |
642 | dev->_irq_audio_queues = | ||
643 | create_singlethread_workqueue("cx25821_audioworkqueue"); | ||
644 | |||
645 | if (!dev->_irq_audio_queues) { | ||
646 | printk(KERN_DEBUG | ||
647 | pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n")); | ||
648 | return -ENOMEM; | ||
649 | } | ||
650 | 640 | ||
651 | dev->_last_index_irq = 0; | 641 | dev->_last_index_irq = 0; |
652 | dev->_audio_is_running = 0; | 642 | dev->_audio_is_running = 0; |
diff --git a/drivers/media/pci/cx25821/cx25821-i2c.c b/drivers/media/pci/cx25821/cx25821-i2c.c index dca37c7dba73..63ba25b82692 100644 --- a/drivers/media/pci/cx25821/cx25821-i2c.c +++ b/drivers/media/pci/cx25821/cx25821-i2c.c | |||
@@ -281,7 +281,7 @@ static u32 cx25821_functionality(struct i2c_adapter *adap) | |||
281 | I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA; | 281 | I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA; |
282 | } | 282 | } |
283 | 283 | ||
284 | static struct i2c_algorithm cx25821_i2c_algo_template = { | 284 | static const struct i2c_algorithm cx25821_i2c_algo_template = { |
285 | .master_xfer = i2c_xfer, | 285 | .master_xfer = i2c_xfer, |
286 | .functionality = cx25821_functionality, | 286 | .functionality = cx25821_functionality, |
287 | #ifdef NEED_ALGO_CONTROL | 287 | #ifdef NEED_ALGO_CONTROL |
diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index adcd09be347d..7ce352a0f2d3 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c | |||
@@ -307,7 +307,7 @@ static void cx25821_stop_streaming(struct vb2_queue *q) | |||
307 | spin_unlock_irqrestore(&dev->slock, flags); | 307 | spin_unlock_irqrestore(&dev->slock, flags); |
308 | } | 308 | } |
309 | 309 | ||
310 | static struct vb2_ops cx25821_video_qops = { | 310 | static const struct vb2_ops cx25821_video_qops = { |
311 | .queue_setup = cx25821_queue_setup, | 311 | .queue_setup = cx25821_queue_setup, |
312 | .buf_prepare = cx25821_buffer_prepare, | 312 | .buf_prepare = cx25821_buffer_prepare, |
313 | .buf_finish = cx25821_buffer_finish, | 313 | .buf_finish = cx25821_buffer_finish, |
diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 35c7375e4617..ef61dea982e8 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h | |||
@@ -293,7 +293,6 @@ struct cx25821_dev { | |||
293 | u32 audio_upstream_riscbuf_size; | 293 | u32 audio_upstream_riscbuf_size; |
294 | u32 audio_upstream_databuf_size; | 294 | u32 audio_upstream_databuf_size; |
295 | int _audioframe_index; | 295 | int _audioframe_index; |
296 | struct workqueue_struct *_irq_audio_queues; | ||
297 | struct work_struct _audio_work_entry; | 296 | struct work_struct _audio_work_entry; |
298 | char *input_audiofilename; | 297 | char *input_audiofilename; |
299 | 298 | ||
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index f3f13eb0c16e..723f06462104 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c | |||
@@ -599,7 +599,7 @@ static struct page *snd_cx88_page(struct snd_pcm_substream *substream, | |||
599 | /* | 599 | /* |
600 | * operators | 600 | * operators |
601 | */ | 601 | */ |
602 | static struct snd_pcm_ops snd_cx88_pcm_ops = { | 602 | static const struct snd_pcm_ops snd_cx88_pcm_ops = { |
603 | .open = snd_cx88_pcm_open, | 603 | .open = snd_cx88_pcm_open, |
604 | .close = snd_cx88_close, | 604 | .close = snd_cx88_close, |
605 | .ioctl = snd_pcm_lib_ioctl, | 605 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 04fe9af2a802..b532e49e8f33 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c | |||
@@ -756,7 +756,7 @@ static void stop_streaming(struct vb2_queue *q) | |||
756 | spin_unlock_irqrestore(&dev->slock, flags); | 756 | spin_unlock_irqrestore(&dev->slock, flags); |
757 | } | 757 | } |
758 | 758 | ||
759 | static struct vb2_ops blackbird_qops = { | 759 | static const struct vb2_ops blackbird_qops = { |
760 | .queue_setup = queue_setup, | 760 | .queue_setup = queue_setup, |
761 | .buf_prepare = buffer_prepare, | 761 | .buf_prepare = buffer_prepare, |
762 | .buf_finish = buffer_finish, | 762 | .buf_finish = buffer_finish, |
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index 5bb63e7a5691..ac2392d8887a 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c | |||
@@ -156,7 +156,7 @@ static void stop_streaming(struct vb2_queue *q) | |||
156 | spin_unlock_irqrestore(&dev->slock, flags); | 156 | spin_unlock_irqrestore(&dev->slock, flags); |
157 | } | 157 | } |
158 | 158 | ||
159 | static struct vb2_ops dvb_qops = { | 159 | static const struct vb2_ops dvb_qops = { |
160 | .queue_setup = queue_setup, | 160 | .queue_setup = queue_setup, |
161 | .buf_prepare = buffer_prepare, | 161 | .buf_prepare = buffer_prepare, |
162 | .buf_finish = buffer_finish, | 162 | .buf_finish = buffer_finish, |
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index 3f1342c98b46..cd7687183381 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c | |||
@@ -144,7 +144,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) | |||
144 | scancode = RC_SCANCODE_NECX(addr, cmd); | 144 | scancode = RC_SCANCODE_NECX(addr, cmd); |
145 | 145 | ||
146 | if (0 == (gpio & ir->mask_keyup)) | 146 | if (0 == (gpio & ir->mask_keyup)) |
147 | rc_keydown_notimeout(ir->dev, RC_TYPE_NEC, scancode, 0); | 147 | rc_keydown_notimeout(ir->dev, RC_TYPE_NECX, scancode, |
148 | 0); | ||
148 | else | 149 | else |
149 | rc_keyup(ir->dev); | 150 | rc_keyup(ir->dev); |
150 | 151 | ||
@@ -345,7 +346,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) | |||
345 | * 002-T mini RC, provided with newer PV hardware | 346 | * 002-T mini RC, provided with newer PV hardware |
346 | */ | 347 | */ |
347 | ir_codes = RC_MAP_PIXELVIEW_MK12; | 348 | ir_codes = RC_MAP_PIXELVIEW_MK12; |
348 | rc_type = RC_BIT_NEC; | 349 | rc_type = RC_BIT_NECX; |
349 | ir->gpio_addr = MO_GP1_IO; | 350 | ir->gpio_addr = MO_GP1_IO; |
350 | ir->mask_keyup = 0x80; | 351 | ir->mask_keyup = 0x80; |
351 | ir->polling = 10; /* ms */ | 352 | ir->polling = 10; /* ms */ |
@@ -631,7 +632,8 @@ void cx88_i2c_init_ir(struct cx88_core *core) | |||
631 | /* Hauppauge XVR */ | 632 | /* Hauppauge XVR */ |
632 | core->init_data.name = "cx88 Hauppauge XVR remote"; | 633 | core->init_data.name = "cx88 Hauppauge XVR remote"; |
633 | core->init_data.ir_codes = RC_MAP_HAUPPAUGE; | 634 | core->init_data.ir_codes = RC_MAP_HAUPPAUGE; |
634 | core->init_data.type = RC_BIT_RC5; | 635 | core->init_data.type = RC_BIT_RC5 | RC_BIT_RC6_MCE | |
636 | RC_BIT_RC6_6A_32; | ||
635 | core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; | 637 | core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; |
636 | 638 | ||
637 | info.platform_data = &core->init_data; | 639 | info.platform_data = &core->init_data; |
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 5dc1e3f08d50..d83eb3b10f54 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c | |||
@@ -567,7 +567,7 @@ static void stop_streaming(struct vb2_queue *q) | |||
567 | spin_unlock_irqrestore(&dev->slock, flags); | 567 | spin_unlock_irqrestore(&dev->slock, flags); |
568 | } | 568 | } |
569 | 569 | ||
570 | static struct vb2_ops cx8800_video_qops = { | 570 | static const struct vb2_ops cx8800_video_qops = { |
571 | .queue_setup = queue_setup, | 571 | .queue_setup = queue_setup, |
572 | .buf_prepare = buffer_prepare, | 572 | .buf_prepare = buffer_prepare, |
573 | .buf_finish = buffer_finish, | 573 | .buf_finish = buffer_finish, |
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index 47def73b3502..18e3a4deee64 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c | |||
@@ -1643,53 +1643,53 @@ fail: | |||
1643 | /******************************************************************************/ | 1643 | /******************************************************************************/ |
1644 | /******************************************************************************/ | 1644 | /******************************************************************************/ |
1645 | 1645 | ||
1646 | static struct ddb_info ddb_none = { | 1646 | static const struct ddb_info ddb_none = { |
1647 | .type = DDB_NONE, | 1647 | .type = DDB_NONE, |
1648 | .name = "Digital Devices PCIe bridge", | 1648 | .name = "Digital Devices PCIe bridge", |
1649 | }; | 1649 | }; |
1650 | 1650 | ||
1651 | static struct ddb_info ddb_octopus = { | 1651 | static const struct ddb_info ddb_octopus = { |
1652 | .type = DDB_OCTOPUS, | 1652 | .type = DDB_OCTOPUS, |
1653 | .name = "Digital Devices Octopus DVB adapter", | 1653 | .name = "Digital Devices Octopus DVB adapter", |
1654 | .port_num = 4, | 1654 | .port_num = 4, |
1655 | }; | 1655 | }; |
1656 | 1656 | ||
1657 | static struct ddb_info ddb_octopus_le = { | 1657 | static const struct ddb_info ddb_octopus_le = { |
1658 | .type = DDB_OCTOPUS, | 1658 | .type = DDB_OCTOPUS, |
1659 | .name = "Digital Devices Octopus LE DVB adapter", | 1659 | .name = "Digital Devices Octopus LE DVB adapter", |
1660 | .port_num = 2, | 1660 | .port_num = 2, |
1661 | }; | 1661 | }; |
1662 | 1662 | ||
1663 | static struct ddb_info ddb_octopus_mini = { | 1663 | static const struct ddb_info ddb_octopus_mini = { |
1664 | .type = DDB_OCTOPUS, | 1664 | .type = DDB_OCTOPUS, |
1665 | .name = "Digital Devices Octopus Mini", | 1665 | .name = "Digital Devices Octopus Mini", |
1666 | .port_num = 4, | 1666 | .port_num = 4, |
1667 | }; | 1667 | }; |
1668 | 1668 | ||
1669 | static struct ddb_info ddb_v6 = { | 1669 | static const struct ddb_info ddb_v6 = { |
1670 | .type = DDB_OCTOPUS, | 1670 | .type = DDB_OCTOPUS, |
1671 | .name = "Digital Devices Cine S2 V6 DVB adapter", | 1671 | .name = "Digital Devices Cine S2 V6 DVB adapter", |
1672 | .port_num = 3, | 1672 | .port_num = 3, |
1673 | }; | 1673 | }; |
1674 | static struct ddb_info ddb_v6_5 = { | 1674 | static const struct ddb_info ddb_v6_5 = { |
1675 | .type = DDB_OCTOPUS, | 1675 | .type = DDB_OCTOPUS, |
1676 | .name = "Digital Devices Cine S2 V6.5 DVB adapter", | 1676 | .name = "Digital Devices Cine S2 V6.5 DVB adapter", |
1677 | .port_num = 4, | 1677 | .port_num = 4, |
1678 | }; | 1678 | }; |
1679 | 1679 | ||
1680 | static struct ddb_info ddb_dvbct = { | 1680 | static const struct ddb_info ddb_dvbct = { |
1681 | .type = DDB_OCTOPUS, | 1681 | .type = DDB_OCTOPUS, |
1682 | .name = "Digital Devices DVBCT V6.1 DVB adapter", | 1682 | .name = "Digital Devices DVBCT V6.1 DVB adapter", |
1683 | .port_num = 3, | 1683 | .port_num = 3, |
1684 | }; | 1684 | }; |
1685 | 1685 | ||
1686 | static struct ddb_info ddb_satixS2v3 = { | 1686 | static const struct ddb_info ddb_satixS2v3 = { |
1687 | .type = DDB_OCTOPUS, | 1687 | .type = DDB_OCTOPUS, |
1688 | .name = "Mystique SaTiX-S2 V3 DVB adapter", | 1688 | .name = "Mystique SaTiX-S2 V3 DVB adapter", |
1689 | .port_num = 3, | 1689 | .port_num = 3, |
1690 | }; | 1690 | }; |
1691 | 1691 | ||
1692 | static struct ddb_info ddb_octopusv3 = { | 1692 | static const struct ddb_info ddb_octopusv3 = { |
1693 | .type = DDB_OCTOPUS, | 1693 | .type = DDB_OCTOPUS, |
1694 | .name = "Digital Devices Octopus V3 DVB adapter", | 1694 | .name = "Digital Devices Octopus V3 DVB adapter", |
1695 | .port_num = 4, | 1695 | .port_num = 4, |
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c index f198b9826ed8..a26f9800eca3 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c | |||
@@ -318,7 +318,7 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, | |||
318 | return vmalloc_to_page(pageptr); | 318 | return vmalloc_to_page(pageptr); |
319 | } | 319 | } |
320 | 320 | ||
321 | static struct snd_pcm_ops snd_ivtv_pcm_capture_ops = { | 321 | static const struct snd_pcm_ops snd_ivtv_pcm_capture_ops = { |
322 | .open = snd_ivtv_pcm_capture_open, | 322 | .open = snd_ivtv_pcm_capture_open, |
323 | .close = snd_ivtv_pcm_capture_close, | 323 | .close = snd_ivtv_pcm_capture_close, |
324 | .ioctl = snd_ivtv_pcm_ioctl, | 324 | .ioctl = snd_ivtv_pcm_ioctl, |
diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c index bccbf2d18e30..dea80efd5836 100644 --- a/drivers/media/pci/ivtv/ivtv-i2c.c +++ b/drivers/media/pci/ivtv/ivtv-i2c.c | |||
@@ -215,7 +215,8 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) | |||
215 | /* Default to grey remote */ | 215 | /* Default to grey remote */ |
216 | init_data->ir_codes = RC_MAP_HAUPPAUGE; | 216 | init_data->ir_codes = RC_MAP_HAUPPAUGE; |
217 | init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; | 217 | init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; |
218 | init_data->type = RC_BIT_RC5; | 218 | init_data->type = RC_BIT_RC5 | RC_BIT_RC6_MCE | |
219 | RC_BIT_RC6_6A_32; | ||
219 | init_data->name = itv->card_name; | 220 | init_data->name = itv->card_name; |
220 | break; | 221 | break; |
221 | case IVTV_HW_I2C_IR_RX_ADAPTEC: | 222 | case IVTV_HW_I2C_IR_RX_ADAPTEC: |
@@ -625,7 +626,7 @@ static u32 ivtv_functionality(struct i2c_adapter *adap) | |||
625 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | 626 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; |
626 | } | 627 | } |
627 | 628 | ||
628 | static struct i2c_algorithm ivtv_algo = { | 629 | static const struct i2c_algorithm ivtv_algo = { |
629 | .master_xfer = ivtv_xfer, | 630 | .master_xfer = ivtv_xfer, |
630 | .functionality = ivtv_functionality, | 631 | .functionality = ivtv_functionality, |
631 | }; | 632 | }; |
diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index ac547cb84de8..b078ac2a682c 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c | |||
@@ -353,7 +353,7 @@ static void netup_unidvb_stop_streaming(struct vb2_queue *q) | |||
353 | netup_unidvb_queue_cleanup(dma); | 353 | netup_unidvb_queue_cleanup(dma); |
354 | } | 354 | } |
355 | 355 | ||
356 | static struct vb2_ops dvb_qops = { | 356 | static const struct vb2_ops dvb_qops = { |
357 | .queue_setup = netup_unidvb_queue_setup, | 357 | .queue_setup = netup_unidvb_queue_setup, |
358 | .buf_prepare = netup_unidvb_buf_prepare, | 358 | .buf_prepare = netup_unidvb_buf_prepare, |
359 | .buf_queue = netup_unidvb_buf_queue, | 359 | .buf_queue = netup_unidvb_buf_queue, |
diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c b/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c index c09c52bc6eab..b49e4f9788e8 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c | |||
@@ -327,11 +327,8 @@ static int netup_i2c_init(struct netup_unidvb_dev *ndev, int bus_num) | |||
327 | i2c->adap.dev.parent = &ndev->pci_dev->dev; | 327 | i2c->adap.dev.parent = &ndev->pci_dev->dev; |
328 | i2c_set_adapdata(&i2c->adap, i2c); | 328 | i2c_set_adapdata(&i2c->adap, i2c); |
329 | ret = i2c_add_adapter(&i2c->adap); | 329 | ret = i2c_add_adapter(&i2c->adap); |
330 | if (ret) { | 330 | if (ret) |
331 | dev_err(&ndev->pci_dev->dev, | ||
332 | "%s(): failed to add I2C adapter\n", __func__); | ||
333 | return ret; | 331 | return ret; |
334 | } | ||
335 | dev_info(&ndev->pci_dev->dev, | 332 | dev_info(&ndev->pci_dev->dev, |
336 | "%s(): registered I2C bus %d at 0x%x\n", | 333 | "%s(): registered I2C bus %d at 0x%x\n", |
337 | __func__, | 334 | __func__, |
diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 4e783a68bf4a..423e8c889310 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c | |||
@@ -613,7 +613,7 @@ static struct stv6110x_config tuner_cineS2_1 = { | |||
613 | .clk_div = 1, | 613 | .clk_div = 1, |
614 | }; | 614 | }; |
615 | 615 | ||
616 | static struct ngene_info ngene_info_cineS2 = { | 616 | static const struct ngene_info ngene_info_cineS2 = { |
617 | .type = NGENE_SIDEWINDER, | 617 | .type = NGENE_SIDEWINDER, |
618 | .name = "Linux4Media cineS2 DVB-S2 Twin Tuner", | 618 | .name = "Linux4Media cineS2 DVB-S2 Twin Tuner", |
619 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, | 619 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, |
@@ -627,7 +627,7 @@ static struct ngene_info ngene_info_cineS2 = { | |||
627 | .msi_supported = true, | 627 | .msi_supported = true, |
628 | }; | 628 | }; |
629 | 629 | ||
630 | static struct ngene_info ngene_info_satixS2 = { | 630 | static const struct ngene_info ngene_info_satixS2 = { |
631 | .type = NGENE_SIDEWINDER, | 631 | .type = NGENE_SIDEWINDER, |
632 | .name = "Mystique SaTiX-S2 Dual", | 632 | .name = "Mystique SaTiX-S2 Dual", |
633 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, | 633 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, |
@@ -641,7 +641,7 @@ static struct ngene_info ngene_info_satixS2 = { | |||
641 | .msi_supported = true, | 641 | .msi_supported = true, |
642 | }; | 642 | }; |
643 | 643 | ||
644 | static struct ngene_info ngene_info_satixS2v2 = { | 644 | static const struct ngene_info ngene_info_satixS2v2 = { |
645 | .type = NGENE_SIDEWINDER, | 645 | .type = NGENE_SIDEWINDER, |
646 | .name = "Mystique SaTiX-S2 Dual (v2)", | 646 | .name = "Mystique SaTiX-S2 Dual (v2)", |
647 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, | 647 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, |
@@ -656,7 +656,7 @@ static struct ngene_info ngene_info_satixS2v2 = { | |||
656 | .msi_supported = true, | 656 | .msi_supported = true, |
657 | }; | 657 | }; |
658 | 658 | ||
659 | static struct ngene_info ngene_info_cineS2v5 = { | 659 | static const struct ngene_info ngene_info_cineS2v5 = { |
660 | .type = NGENE_SIDEWINDER, | 660 | .type = NGENE_SIDEWINDER, |
661 | .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)", | 661 | .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)", |
662 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, | 662 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, |
@@ -672,7 +672,7 @@ static struct ngene_info ngene_info_cineS2v5 = { | |||
672 | }; | 672 | }; |
673 | 673 | ||
674 | 674 | ||
675 | static struct ngene_info ngene_info_duoFlex = { | 675 | static const struct ngene_info ngene_info_duoFlex = { |
676 | .type = NGENE_SIDEWINDER, | 676 | .type = NGENE_SIDEWINDER, |
677 | .name = "Digital Devices DuoFlex PCIe or miniPCIe", | 677 | .name = "Digital Devices DuoFlex PCIe or miniPCIe", |
678 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, | 678 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, |
@@ -687,7 +687,7 @@ static struct ngene_info ngene_info_duoFlex = { | |||
687 | .msi_supported = true, | 687 | .msi_supported = true, |
688 | }; | 688 | }; |
689 | 689 | ||
690 | static struct ngene_info ngene_info_m780 = { | 690 | static const struct ngene_info ngene_info_m780 = { |
691 | .type = NGENE_APP, | 691 | .type = NGENE_APP, |
692 | .name = "Aver M780 ATSC/QAM-B", | 692 | .name = "Aver M780 ATSC/QAM-B", |
693 | 693 | ||
@@ -727,7 +727,7 @@ static struct drxd_config fe_terratec_dvbt_1 = { | |||
727 | .osc_deviation = osc_deviation, | 727 | .osc_deviation = osc_deviation, |
728 | }; | 728 | }; |
729 | 729 | ||
730 | static struct ngene_info ngene_info_terratec = { | 730 | static const struct ngene_info ngene_info_terratec = { |
731 | .type = NGENE_TERRATEC, | 731 | .type = NGENE_TERRATEC, |
732 | .name = "Terratec Integra/Cinergy2400i Dual DVB-T", | 732 | .name = "Terratec Integra/Cinergy2400i Dual DVB-T", |
733 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, | 733 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, |
diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c index eff5e9f51ace..7fb649e523f4 100644 --- a/drivers/media/pci/pt3/pt3.c +++ b/drivers/media/pci/pt3/pt3.c | |||
@@ -798,10 +798,8 @@ static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
798 | strlcpy(i2c->name, DRV_NAME, sizeof(i2c->name)); | 798 | strlcpy(i2c->name, DRV_NAME, sizeof(i2c->name)); |
799 | i2c_set_adapdata(i2c, pt3); | 799 | i2c_set_adapdata(i2c, pt3); |
800 | ret = i2c_add_adapter(i2c); | 800 | ret = i2c_add_adapter(i2c); |
801 | if (ret < 0) { | 801 | if (ret < 0) |
802 | dev_err(&pdev->dev, "Failed to add i2c adapter\n"); | ||
803 | goto err_i2cbuf; | 802 | goto err_i2cbuf; |
804 | } | ||
805 | 803 | ||
806 | for (i = 0; i < PT3_NUM_FE; i++) { | 804 | for (i = 0; i < PT3_NUM_FE; i++) { |
807 | ret = pt3_alloc_adapter(pt3, i); | 805 | ret = pt3_alloc_adapter(pt3, i); |
diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index 94f816244407..dc0e2fc5f68b 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c | |||
@@ -877,7 +877,7 @@ static struct page *snd_card_saa7134_page(struct snd_pcm_substream *substream, | |||
877 | * ALSA capture callbacks definition | 877 | * ALSA capture callbacks definition |
878 | */ | 878 | */ |
879 | 879 | ||
880 | static struct snd_pcm_ops snd_card_saa7134_capture_ops = { | 880 | static const struct snd_pcm_ops snd_card_saa7134_capture_ops = { |
881 | .open = snd_card_saa7134_capture_open, | 881 | .open = snd_card_saa7134_capture_open, |
882 | .close = snd_card_saa7134_capture_close, | 882 | .close = snd_card_saa7134_capture_close, |
883 | .ioctl = snd_pcm_lib_ioctl, | 883 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 791a5161809b..f0fe2524259f 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c | |||
@@ -85,7 +85,7 @@ static void stop_streaming(struct vb2_queue *vq) | |||
85 | dev->empress_started = 0; | 85 | dev->empress_started = 0; |
86 | } | 86 | } |
87 | 87 | ||
88 | static struct vb2_ops saa7134_empress_qops = { | 88 | static const struct vb2_ops saa7134_empress_qops = { |
89 | .queue_setup = saa7134_ts_queue_setup, | 89 | .queue_setup = saa7134_ts_queue_setup, |
90 | .buf_init = saa7134_ts_buffer_init, | 90 | .buf_init = saa7134_ts_buffer_init, |
91 | .buf_prepare = saa7134_ts_buffer_prepare, | 91 | .buf_prepare = saa7134_ts_buffer_prepare, |
diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c index 8ef6399d794f..2dac48fa1386 100644 --- a/drivers/media/pci/saa7134/saa7134-i2c.c +++ b/drivers/media/pci/saa7134/saa7134-i2c.c | |||
@@ -338,7 +338,7 @@ static u32 functionality(struct i2c_adapter *adap) | |||
338 | return I2C_FUNC_SMBUS_EMUL; | 338 | return I2C_FUNC_SMBUS_EMUL; |
339 | } | 339 | } |
340 | 340 | ||
341 | static struct i2c_algorithm saa7134_algo = { | 341 | static const struct i2c_algorithm saa7134_algo = { |
342 | .master_xfer = saa7134_i2c_xfer, | 342 | .master_xfer = saa7134_i2c_xfer, |
343 | .functionality = functionality, | 343 | .functionality = functionality, |
344 | }; | 344 | }; |
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c index c8042c3888cd..eff52bbbfd66 100644 --- a/drivers/media/pci/saa7134/saa7134-input.c +++ b/drivers/media/pci/saa7134/saa7134-input.c | |||
@@ -345,7 +345,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol, | |||
345 | if (data[9] != (unsigned char)(~data[8])) | 345 | if (data[9] != (unsigned char)(~data[8])) |
346 | return 0; | 346 | return 0; |
347 | 347 | ||
348 | *protocol = RC_TYPE_NEC; | 348 | *protocol = RC_TYPE_NECX; |
349 | *scancode = RC_SCANCODE_NECX(data[11] << 8 | data[10], data[9]); | 349 | *scancode = RC_SCANCODE_NECX(data[11] << 8 | data[10], data[9]); |
350 | *toggle = 0; | 350 | *toggle = 0; |
351 | return 1; | 351 | return 1; |
@@ -1035,7 +1035,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) | |||
1035 | dev->init_data.name = "BeholdTV"; | 1035 | dev->init_data.name = "BeholdTV"; |
1036 | dev->init_data.get_key = get_key_beholdm6xx; | 1036 | dev->init_data.get_key = get_key_beholdm6xx; |
1037 | dev->init_data.ir_codes = RC_MAP_BEHOLD; | 1037 | dev->init_data.ir_codes = RC_MAP_BEHOLD; |
1038 | dev->init_data.type = RC_BIT_NEC; | 1038 | dev->init_data.type = RC_BIT_NECX; |
1039 | info.addr = 0x2d; | 1039 | info.addr = 0x2d; |
1040 | break; | 1040 | break; |
1041 | case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: | 1041 | case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: |
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 8a6ebd087889..cbb173d99085 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c | |||
@@ -1054,7 +1054,7 @@ void saa7134_vb2_stop_streaming(struct vb2_queue *vq) | |||
1054 | pm_qos_remove_request(&dev->qos_request); | 1054 | pm_qos_remove_request(&dev->qos_request); |
1055 | } | 1055 | } |
1056 | 1056 | ||
1057 | static struct vb2_ops vb2_qops = { | 1057 | static const struct vb2_ops vb2_qops = { |
1058 | .queue_setup = queue_setup, | 1058 | .queue_setup = queue_setup, |
1059 | .buf_init = buffer_init, | 1059 | .buf_init = buffer_init, |
1060 | .buf_prepare = buffer_prepare, | 1060 | .buf_prepare = buffer_prepare, |
@@ -1659,8 +1659,6 @@ static int saa7134_cropcap(struct file *file, void *priv, | |||
1659 | if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | 1659 | if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
1660 | cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | 1660 | cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) |
1661 | return -EINVAL; | 1661 | return -EINVAL; |
1662 | cap->bounds = dev->crop_bounds; | ||
1663 | cap->defrect = dev->crop_defrect; | ||
1664 | cap->pixelaspect.numerator = 1; | 1662 | cap->pixelaspect.numerator = 1; |
1665 | cap->pixelaspect.denominator = 1; | 1663 | cap->pixelaspect.denominator = 1; |
1666 | if (dev->tvnorm->id & V4L2_STD_525_60) { | 1664 | if (dev->tvnorm->id & V4L2_STD_525_60) { |
@@ -1674,25 +1672,41 @@ static int saa7134_cropcap(struct file *file, void *priv, | |||
1674 | return 0; | 1672 | return 0; |
1675 | } | 1673 | } |
1676 | 1674 | ||
1677 | static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop) | 1675 | static int saa7134_g_selection(struct file *file, void *f, struct v4l2_selection *sel) |
1678 | { | 1676 | { |
1679 | struct saa7134_dev *dev = video_drvdata(file); | 1677 | struct saa7134_dev *dev = video_drvdata(file); |
1680 | 1678 | ||
1681 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | 1679 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
1682 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | 1680 | sel->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) |
1683 | return -EINVAL; | 1681 | return -EINVAL; |
1684 | crop->c = dev->crop_current; | 1682 | |
1683 | switch (sel->target) { | ||
1684 | case V4L2_SEL_TGT_CROP: | ||
1685 | sel->r = dev->crop_current; | ||
1686 | break; | ||
1687 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
1688 | sel->r = dev->crop_defrect; | ||
1689 | break; | ||
1690 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
1691 | sel->r = dev->crop_bounds; | ||
1692 | break; | ||
1693 | default: | ||
1694 | return -EINVAL; | ||
1695 | } | ||
1685 | return 0; | 1696 | return 0; |
1686 | } | 1697 | } |
1687 | 1698 | ||
1688 | static int saa7134_s_crop(struct file *file, void *f, const struct v4l2_crop *crop) | 1699 | static int saa7134_s_selection(struct file *file, void *f, struct v4l2_selection *sel) |
1689 | { | 1700 | { |
1690 | struct saa7134_dev *dev = video_drvdata(file); | 1701 | struct saa7134_dev *dev = video_drvdata(file); |
1691 | struct v4l2_rect *b = &dev->crop_bounds; | 1702 | struct v4l2_rect *b = &dev->crop_bounds; |
1692 | struct v4l2_rect *c = &dev->crop_current; | 1703 | struct v4l2_rect *c = &dev->crop_current; |
1693 | 1704 | ||
1694 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | 1705 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && |
1695 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | 1706 | sel->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) |
1707 | return -EINVAL; | ||
1708 | |||
1709 | if (sel->target != V4L2_SEL_TGT_CROP) | ||
1696 | return -EINVAL; | 1710 | return -EINVAL; |
1697 | 1711 | ||
1698 | if (dev->overlay_owner) | 1712 | if (dev->overlay_owner) |
@@ -1700,7 +1714,7 @@ static int saa7134_s_crop(struct file *file, void *f, const struct v4l2_crop *cr | |||
1700 | if (vb2_is_streaming(&dev->video_vbq)) | 1714 | if (vb2_is_streaming(&dev->video_vbq)) |
1701 | return -EBUSY; | 1715 | return -EBUSY; |
1702 | 1716 | ||
1703 | *c = crop->c; | 1717 | *c = sel->r; |
1704 | if (c->top < b->top) | 1718 | if (c->top < b->top) |
1705 | c->top = b->top; | 1719 | c->top = b->top; |
1706 | if (c->top > b->top + b->height) | 1720 | if (c->top > b->top + b->height) |
@@ -1714,6 +1728,7 @@ static int saa7134_s_crop(struct file *file, void *f, const struct v4l2_crop *cr | |||
1714 | c->left = b->left + b->width; | 1728 | c->left = b->left + b->width; |
1715 | if (c->width > b->left - c->left + b->width) | 1729 | if (c->width > b->left - c->left + b->width) |
1716 | c->width = b->left - c->left + b->width; | 1730 | c->width = b->left - c->left + b->width; |
1731 | sel->r = *c; | ||
1717 | return 0; | 1732 | return 0; |
1718 | } | 1733 | } |
1719 | 1734 | ||
@@ -1989,8 +2004,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
1989 | .vidioc_streamoff = vb2_ioctl_streamoff, | 2004 | .vidioc_streamoff = vb2_ioctl_streamoff, |
1990 | .vidioc_g_tuner = saa7134_g_tuner, | 2005 | .vidioc_g_tuner = saa7134_g_tuner, |
1991 | .vidioc_s_tuner = saa7134_s_tuner, | 2006 | .vidioc_s_tuner = saa7134_s_tuner, |
1992 | .vidioc_g_crop = saa7134_g_crop, | 2007 | .vidioc_g_selection = saa7134_g_selection, |
1993 | .vidioc_s_crop = saa7134_s_crop, | 2008 | .vidioc_s_selection = saa7134_s_selection, |
1994 | .vidioc_g_fbuf = saa7134_g_fbuf, | 2009 | .vidioc_g_fbuf = saa7134_g_fbuf, |
1995 | .vidioc_s_fbuf = saa7134_s_fbuf, | 2010 | .vidioc_s_fbuf = saa7134_s_fbuf, |
1996 | .vidioc_overlay = saa7134_overlay, | 2011 | .vidioc_overlay = saa7134_overlay, |
diff --git a/drivers/media/pci/saa7164/saa7164-i2c.c b/drivers/media/pci/saa7164/saa7164-i2c.c index 0342d84913b8..024f4e29e840 100644 --- a/drivers/media/pci/saa7164/saa7164-i2c.c +++ b/drivers/media/pci/saa7164/saa7164-i2c.c | |||
@@ -75,7 +75,7 @@ static u32 saa7164_functionality(struct i2c_adapter *adap) | |||
75 | return I2C_FUNC_I2C; | 75 | return I2C_FUNC_I2C; |
76 | } | 76 | } |
77 | 77 | ||
78 | static struct i2c_algorithm saa7164_i2c_algo_template = { | 78 | static const struct i2c_algorithm saa7164_i2c_algo_template = { |
79 | .master_xfer = i2c_xfer, | 79 | .master_xfer = i2c_xfer, |
80 | .functionality = saa7164_functionality, | 80 | .functionality = saa7164_functionality, |
81 | }; | 81 | }; |
diff --git a/drivers/media/pci/smipcie/smipcie-main.c b/drivers/media/pci/smipcie/smipcie-main.c index 83981d611a79..6dbe3b4d09ce 100644 --- a/drivers/media/pci/smipcie/smipcie-main.c +++ b/drivers/media/pci/smipcie/smipcie-main.c | |||
@@ -1060,7 +1060,7 @@ static void smi_remove(struct pci_dev *pdev) | |||
1060 | } | 1060 | } |
1061 | 1061 | ||
1062 | /* DVBSky cards */ | 1062 | /* DVBSky cards */ |
1063 | static struct smi_cfg_info dvbsky_s950_cfg = { | 1063 | static const struct smi_cfg_info dvbsky_s950_cfg = { |
1064 | .type = SMI_DVBSKY_S950, | 1064 | .type = SMI_DVBSKY_S950, |
1065 | .name = "DVBSky S950 V3", | 1065 | .name = "DVBSky S950 V3", |
1066 | .ts_0 = SMI_TS_NULL, | 1066 | .ts_0 = SMI_TS_NULL, |
@@ -1070,7 +1070,7 @@ static struct smi_cfg_info dvbsky_s950_cfg = { | |||
1070 | .rc_map = RC_MAP_DVBSKY, | 1070 | .rc_map = RC_MAP_DVBSKY, |
1071 | }; | 1071 | }; |
1072 | 1072 | ||
1073 | static struct smi_cfg_info dvbsky_s952_cfg = { | 1073 | static const struct smi_cfg_info dvbsky_s952_cfg = { |
1074 | .type = SMI_DVBSKY_S952, | 1074 | .type = SMI_DVBSKY_S952, |
1075 | .name = "DVBSky S952 V3", | 1075 | .name = "DVBSky S952 V3", |
1076 | .ts_0 = SMI_TS_DMA_BOTH, | 1076 | .ts_0 = SMI_TS_DMA_BOTH, |
@@ -1080,7 +1080,7 @@ static struct smi_cfg_info dvbsky_s952_cfg = { | |||
1080 | .rc_map = RC_MAP_DVBSKY, | 1080 | .rc_map = RC_MAP_DVBSKY, |
1081 | }; | 1081 | }; |
1082 | 1082 | ||
1083 | static struct smi_cfg_info dvbsky_t9580_cfg = { | 1083 | static const struct smi_cfg_info dvbsky_t9580_cfg = { |
1084 | .type = SMI_DVBSKY_T9580, | 1084 | .type = SMI_DVBSKY_T9580, |
1085 | .name = "DVBSky T9580 V3", | 1085 | .name = "DVBSky T9580 V3", |
1086 | .ts_0 = SMI_TS_DMA_BOTH, | 1086 | .ts_0 = SMI_TS_DMA_BOTH, |
@@ -1090,7 +1090,7 @@ static struct smi_cfg_info dvbsky_t9580_cfg = { | |||
1090 | .rc_map = RC_MAP_DVBSKY, | 1090 | .rc_map = RC_MAP_DVBSKY, |
1091 | }; | 1091 | }; |
1092 | 1092 | ||
1093 | static struct smi_cfg_info technotrend_s2_4200_cfg = { | 1093 | static const struct smi_cfg_info technotrend_s2_4200_cfg = { |
1094 | .type = SMI_TECHNOTREND_S2_4200, | 1094 | .type = SMI_TECHNOTREND_S2_4200, |
1095 | .name = "TechnoTrend TT-budget S2-4200 Twin", | 1095 | .name = "TechnoTrend TT-budget S2-4200 Twin", |
1096 | .ts_0 = SMI_TS_DMA_BOTH, | 1096 | .ts_0 = SMI_TS_DMA_BOTH, |
diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 4a37a1c51c48..6a35107aca25 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c | |||
@@ -252,7 +252,7 @@ static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel, | |||
252 | return 0; | 252 | return 0; |
253 | } | 253 | } |
254 | 254 | ||
255 | static struct snd_pcm_ops snd_solo_pcm_ops = { | 255 | static const struct snd_pcm_ops snd_solo_pcm_ops = { |
256 | .open = snd_solo_pcm_open, | 256 | .open = snd_solo_pcm_open, |
257 | .close = snd_solo_pcm_close, | 257 | .close = snd_solo_pcm_close, |
258 | .ioctl = snd_pcm_lib_ioctl, | 258 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 399164314c28..25a2137ab799 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c | |||
@@ -759,7 +759,7 @@ static void solo_enc_buf_finish(struct vb2_buffer *vb) | |||
759 | } | 759 | } |
760 | } | 760 | } |
761 | 761 | ||
762 | static struct vb2_ops solo_enc_video_qops = { | 762 | static const struct vb2_ops solo_enc_video_qops = { |
763 | .queue_setup = solo_enc_queue_setup, | 763 | .queue_setup = solo_enc_queue_setup, |
764 | .buf_queue = solo_enc_buf_queue, | 764 | .buf_queue = solo_enc_buf_queue, |
765 | .buf_finish = solo_enc_buf_finish, | 765 | .buf_finish = solo_enc_buf_finish, |
diff --git a/drivers/media/pci/tw5864/Kconfig b/drivers/media/pci/tw5864/Kconfig new file mode 100644 index 000000000000..87c8f327e2d4 --- /dev/null +++ b/drivers/media/pci/tw5864/Kconfig | |||
@@ -0,0 +1,12 @@ | |||
1 | config VIDEO_TW5864 | ||
2 | tristate "Techwell TW5864 video/audio grabber and encoder" | ||
3 | depends on VIDEO_DEV && PCI && VIDEO_V4L2 | ||
4 | depends on HAS_DMA | ||
5 | select VIDEOBUF2_DMA_CONTIG | ||
6 | ---help--- | ||
7 | Support for boards based on Techwell TW5864 chip which provides | ||
8 | multichannel video & audio grabbing and encoding (H.264, MJPEG, | ||
9 | ADPCM G.726). | ||
10 | |||
11 | To compile this driver as a module, choose M here: the | ||
12 | module will be called tw5864. | ||
diff --git a/drivers/media/pci/tw5864/Makefile b/drivers/media/pci/tw5864/Makefile new file mode 100644 index 000000000000..4fc8b3b1a45a --- /dev/null +++ b/drivers/media/pci/tw5864/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | tw5864-objs := tw5864-core.o tw5864-video.o tw5864-h264.o tw5864-util.o | ||
2 | |||
3 | obj-$(CONFIG_VIDEO_TW5864) += tw5864.o | ||
diff --git a/drivers/media/pci/tw5864/tw5864-core.c b/drivers/media/pci/tw5864/tw5864-core.c new file mode 100644 index 000000000000..1d43b96958ea --- /dev/null +++ b/drivers/media/pci/tw5864/tw5864-core.c | |||
@@ -0,0 +1,359 @@ | |||
1 | /* | ||
2 | * TW5864 driver - core functions | ||
3 | * | ||
4 | * Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/list.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/kmod.h> | ||
23 | #include <linux/sound.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/dma-mapping.h> | ||
27 | #include <linux/pm.h> | ||
28 | #include <linux/pci_ids.h> | ||
29 | #include <linux/jiffies.h> | ||
30 | #include <asm/dma.h> | ||
31 | #include <media/v4l2-dev.h> | ||
32 | |||
33 | #include "tw5864.h" | ||
34 | #include "tw5864-reg.h" | ||
35 | |||
36 | MODULE_DESCRIPTION("V4L2 driver module for tw5864-based multimedia capture & encoding devices"); | ||
37 | MODULE_AUTHOR("Bluecherry Maintainers <maintainers@bluecherrydvr.com>"); | ||
38 | MODULE_AUTHOR("Andrey Utkin <andrey.utkin@corp.bluecherry.net>"); | ||
39 | MODULE_LICENSE("GPL"); | ||
40 | |||
41 | /* | ||
42 | * BEWARE OF KNOWN ISSUES WITH VIDEO QUALITY | ||
43 | * | ||
44 | * This driver was developed by Bluecherry LLC by deducing behaviour of | ||
45 | * original manufacturer's driver, from both source code and execution traces. | ||
46 | * It is known that there are some artifacts on output video with this driver: | ||
47 | * - on all known hardware samples: random pixels of wrong color (mostly | ||
48 | * white, red or blue) appearing and disappearing on sequences of P-frames; | ||
49 | * - on some hardware samples (known with H.264 core version e006:2800): | ||
50 | * total madness on P-frames: blocks of wrong luminance; blocks of wrong | ||
51 | * colors "creeping" across the picture. | ||
52 | * There is a workaround for both issues: avoid P-frames by setting GOP size | ||
53 | * to 1. To do that, run this command on device files created by this driver: | ||
54 | * | ||
55 | * v4l2-ctl --device /dev/videoX --set-ctrl=video_gop_size=1 | ||
56 | * | ||
57 | * These issues are not decoding errors; all produced H.264 streams are decoded | ||
58 | * properly. Streams without P-frames don't have these artifacts so it's not | ||
59 | * analog-to-digital conversion issues nor internal memory errors; we conclude | ||
60 | * it's internal H.264 encoder issues. | ||
61 | * We cannot even check the original driver's behaviour because it has never | ||
62 | * worked properly at all in our development environment. So these issues may | ||
63 | * be actually related to firmware or hardware. However it may be that there's | ||
64 | * just some more register settings missing in the driver which would please | ||
65 | * the hardware. | ||
66 | * Manufacturer didn't help much on our inquiries, but feel free to disturb | ||
67 | * again the support of Intersil (owner of former Techwell). | ||
68 | */ | ||
69 | |||
70 | /* take first free /dev/videoX indexes by default */ | ||
71 | static unsigned int video_nr[] = {[0 ... (TW5864_INPUTS - 1)] = -1 }; | ||
72 | |||
73 | module_param_array(video_nr, int, NULL, 0444); | ||
74 | MODULE_PARM_DESC(video_nr, "video devices numbers array"); | ||
75 | |||
76 | /* | ||
77 | * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps | ||
78 | * the PCI ID database up to date. Note that the entries must be | ||
79 | * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. | ||
80 | */ | ||
81 | static const struct pci_device_id tw5864_pci_tbl[] = { | ||
82 | {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_5864)}, | ||
83 | {0,} | ||
84 | }; | ||
85 | |||
86 | void tw5864_irqmask_apply(struct tw5864_dev *dev) | ||
87 | { | ||
88 | tw_writel(TW5864_INTR_ENABLE_L, dev->irqmask & 0xffff); | ||
89 | tw_writel(TW5864_INTR_ENABLE_H, (dev->irqmask >> 16)); | ||
90 | } | ||
91 | |||
92 | static void tw5864_interrupts_disable(struct tw5864_dev *dev) | ||
93 | { | ||
94 | unsigned long flags; | ||
95 | |||
96 | spin_lock_irqsave(&dev->slock, flags); | ||
97 | dev->irqmask = 0; | ||
98 | tw5864_irqmask_apply(dev); | ||
99 | spin_unlock_irqrestore(&dev->slock, flags); | ||
100 | } | ||
101 | |||
102 | static void tw5864_timer_isr(struct tw5864_dev *dev); | ||
103 | static void tw5864_h264_isr(struct tw5864_dev *dev); | ||
104 | |||
105 | static irqreturn_t tw5864_isr(int irq, void *dev_id) | ||
106 | { | ||
107 | struct tw5864_dev *dev = dev_id; | ||
108 | u32 status; | ||
109 | |||
110 | status = tw_readl(TW5864_INTR_STATUS_L) | | ||
111 | tw_readl(TW5864_INTR_STATUS_H) << 16; | ||
112 | if (!status) | ||
113 | return IRQ_NONE; | ||
114 | |||
115 | tw_writel(TW5864_INTR_CLR_L, 0xffff); | ||
116 | tw_writel(TW5864_INTR_CLR_H, 0xffff); | ||
117 | |||
118 | if (status & TW5864_INTR_VLC_DONE) | ||
119 | tw5864_h264_isr(dev); | ||
120 | |||
121 | if (status & TW5864_INTR_TIMER) | ||
122 | tw5864_timer_isr(dev); | ||
123 | |||
124 | if (!(status & (TW5864_INTR_TIMER | TW5864_INTR_VLC_DONE))) { | ||
125 | dev_dbg(&dev->pci->dev, "Unknown interrupt, status 0x%08X\n", | ||
126 | status); | ||
127 | } | ||
128 | |||
129 | return IRQ_HANDLED; | ||
130 | } | ||
131 | |||
132 | static void tw5864_h264_isr(struct tw5864_dev *dev) | ||
133 | { | ||
134 | int channel = tw_readl(TW5864_DSP) & TW5864_DSP_ENC_CHN; | ||
135 | struct tw5864_input *input = &dev->inputs[channel]; | ||
136 | int cur_frame_index, next_frame_index; | ||
137 | struct tw5864_h264_frame *cur_frame, *next_frame; | ||
138 | unsigned long flags; | ||
139 | |||
140 | spin_lock_irqsave(&dev->slock, flags); | ||
141 | |||
142 | cur_frame_index = dev->h264_buf_w_index; | ||
143 | next_frame_index = (cur_frame_index + 1) % H264_BUF_CNT; | ||
144 | cur_frame = &dev->h264_buf[cur_frame_index]; | ||
145 | next_frame = &dev->h264_buf[next_frame_index]; | ||
146 | |||
147 | if (next_frame_index != dev->h264_buf_r_index) { | ||
148 | cur_frame->vlc_len = tw_readl(TW5864_VLC_LENGTH) << 2; | ||
149 | cur_frame->checksum = tw_readl(TW5864_VLC_CRC_REG); | ||
150 | cur_frame->input = input; | ||
151 | cur_frame->timestamp = ktime_get_ns(); | ||
152 | cur_frame->seqno = input->frame_seqno; | ||
153 | cur_frame->gop_seqno = input->frame_gop_seqno; | ||
154 | |||
155 | dev->h264_buf_w_index = next_frame_index; | ||
156 | tasklet_schedule(&dev->tasklet); | ||
157 | |||
158 | cur_frame = next_frame; | ||
159 | |||
160 | spin_lock(&input->slock); | ||
161 | input->frame_seqno++; | ||
162 | input->frame_gop_seqno++; | ||
163 | if (input->frame_gop_seqno >= input->gop) | ||
164 | input->frame_gop_seqno = 0; | ||
165 | spin_unlock(&input->slock); | ||
166 | } else { | ||
167 | dev_err(&dev->pci->dev, | ||
168 | "Skipped frame on input %d because all buffers busy\n", | ||
169 | channel); | ||
170 | } | ||
171 | |||
172 | dev->encoder_busy = 0; | ||
173 | |||
174 | spin_unlock_irqrestore(&dev->slock, flags); | ||
175 | |||
176 | tw_writel(TW5864_VLC_STREAM_BASE_ADDR, cur_frame->vlc.dma_addr); | ||
177 | tw_writel(TW5864_MV_STREAM_BASE_ADDR, cur_frame->mv.dma_addr); | ||
178 | |||
179 | /* Additional ack for this interrupt */ | ||
180 | tw_writel(TW5864_VLC_DSP_INTR, 0x00000001); | ||
181 | tw_writel(TW5864_PCI_INTR_STATUS, TW5864_VLC_DONE_INTR); | ||
182 | } | ||
183 | |||
184 | static void tw5864_input_deadline_update(struct tw5864_input *input) | ||
185 | { | ||
186 | input->new_frame_deadline = jiffies + msecs_to_jiffies(1000); | ||
187 | } | ||
188 | |||
189 | static void tw5864_timer_isr(struct tw5864_dev *dev) | ||
190 | { | ||
191 | unsigned long flags; | ||
192 | int i; | ||
193 | int encoder_busy; | ||
194 | |||
195 | /* Additional ack for this interrupt */ | ||
196 | tw_writel(TW5864_PCI_INTR_STATUS, TW5864_TIMER_INTR); | ||
197 | |||
198 | spin_lock_irqsave(&dev->slock, flags); | ||
199 | encoder_busy = dev->encoder_busy; | ||
200 | spin_unlock_irqrestore(&dev->slock, flags); | ||
201 | |||
202 | if (encoder_busy) | ||
203 | return; | ||
204 | |||
205 | /* | ||
206 | * Traversing inputs in round-robin fashion, starting from next to the | ||
207 | * last processed one | ||
208 | */ | ||
209 | for (i = 0; i < TW5864_INPUTS; i++) { | ||
210 | int next_input = (i + dev->next_input) % TW5864_INPUTS; | ||
211 | struct tw5864_input *input = &dev->inputs[next_input]; | ||
212 | int raw_buf_id; /* id of internal buf with last raw frame */ | ||
213 | |||
214 | spin_lock_irqsave(&input->slock, flags); | ||
215 | if (!input->enabled) | ||
216 | goto next; | ||
217 | |||
218 | /* Check if new raw frame is available */ | ||
219 | raw_buf_id = tw_mask_shift_readl(TW5864_SENIF_ORG_FRM_PTR1, 0x3, | ||
220 | 2 * input->nr); | ||
221 | |||
222 | if (input->buf_id != raw_buf_id) { | ||
223 | input->buf_id = raw_buf_id; | ||
224 | tw5864_input_deadline_update(input); | ||
225 | spin_unlock_irqrestore(&input->slock, flags); | ||
226 | |||
227 | spin_lock_irqsave(&dev->slock, flags); | ||
228 | dev->encoder_busy = 1; | ||
229 | dev->next_input = (next_input + 1) % TW5864_INPUTS; | ||
230 | spin_unlock_irqrestore(&dev->slock, flags); | ||
231 | |||
232 | tw5864_request_encoded_frame(input); | ||
233 | break; | ||
234 | } | ||
235 | |||
236 | /* No new raw frame; check if channel is stuck */ | ||
237 | if (time_is_after_jiffies(input->new_frame_deadline)) { | ||
238 | /* If stuck, request new raw frames again */ | ||
239 | tw_mask_shift_writel(TW5864_ENC_BUF_PTR_REC1, 0x3, | ||
240 | 2 * input->nr, input->buf_id + 3); | ||
241 | tw5864_input_deadline_update(input); | ||
242 | } | ||
243 | next: | ||
244 | spin_unlock_irqrestore(&input->slock, flags); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | static int tw5864_initdev(struct pci_dev *pci_dev, | ||
249 | const struct pci_device_id *pci_id) | ||
250 | { | ||
251 | struct tw5864_dev *dev; | ||
252 | int err; | ||
253 | |||
254 | dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev), GFP_KERNEL); | ||
255 | if (!dev) | ||
256 | return -ENOMEM; | ||
257 | |||
258 | snprintf(dev->name, sizeof(dev->name), "tw5864:%s", pci_name(pci_dev)); | ||
259 | |||
260 | err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); | ||
261 | if (err) | ||
262 | return err; | ||
263 | |||
264 | /* pci init */ | ||
265 | dev->pci = pci_dev; | ||
266 | err = pci_enable_device(pci_dev); | ||
267 | if (err) { | ||
268 | dev_err(&dev->pci->dev, "pci_enable_device() failed\n"); | ||
269 | goto unreg_v4l2; | ||
270 | } | ||
271 | |||
272 | pci_set_master(pci_dev); | ||
273 | |||
274 | err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); | ||
275 | if (err) { | ||
276 | dev_err(&dev->pci->dev, "32 bit PCI DMA is not supported\n"); | ||
277 | goto disable_pci; | ||
278 | } | ||
279 | |||
280 | /* get mmio */ | ||
281 | err = pci_request_regions(pci_dev, dev->name); | ||
282 | if (err) { | ||
283 | dev_err(&dev->pci->dev, "Cannot request regions for MMIO\n"); | ||
284 | goto disable_pci; | ||
285 | } | ||
286 | dev->mmio = pci_ioremap_bar(pci_dev, 0); | ||
287 | if (!dev->mmio) { | ||
288 | err = -EIO; | ||
289 | dev_err(&dev->pci->dev, "can't ioremap() MMIO memory\n"); | ||
290 | goto release_mmio; | ||
291 | } | ||
292 | |||
293 | spin_lock_init(&dev->slock); | ||
294 | |||
295 | dev_info(&pci_dev->dev, "TW5864 hardware version: %04x\n", | ||
296 | tw_readl(TW5864_HW_VERSION)); | ||
297 | dev_info(&pci_dev->dev, "TW5864 H.264 core version: %04x:%04x\n", | ||
298 | tw_readl(TW5864_H264REV), | ||
299 | tw_readl(TW5864_UNDECLARED_H264REV_PART2)); | ||
300 | |||
301 | err = tw5864_video_init(dev, video_nr); | ||
302 | if (err) | ||
303 | goto unmap_mmio; | ||
304 | |||
305 | /* get irq */ | ||
306 | err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw5864_isr, | ||
307 | IRQF_SHARED, "tw5864", dev); | ||
308 | if (err < 0) { | ||
309 | dev_err(&dev->pci->dev, "can't get IRQ %d\n", pci_dev->irq); | ||
310 | goto fini_video; | ||
311 | } | ||
312 | |||
313 | dev_info(&pci_dev->dev, "Note: there are known video quality issues. For details\n"); | ||
314 | dev_info(&pci_dev->dev, "see the comment in drivers/media/pci/tw5864/tw5864-core.c.\n"); | ||
315 | |||
316 | return 0; | ||
317 | |||
318 | fini_video: | ||
319 | tw5864_video_fini(dev); | ||
320 | unmap_mmio: | ||
321 | iounmap(dev->mmio); | ||
322 | release_mmio: | ||
323 | pci_release_regions(pci_dev); | ||
324 | disable_pci: | ||
325 | pci_disable_device(pci_dev); | ||
326 | unreg_v4l2: | ||
327 | v4l2_device_unregister(&dev->v4l2_dev); | ||
328 | return err; | ||
329 | } | ||
330 | |||
331 | static void tw5864_finidev(struct pci_dev *pci_dev) | ||
332 | { | ||
333 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); | ||
334 | struct tw5864_dev *dev = | ||
335 | container_of(v4l2_dev, struct tw5864_dev, v4l2_dev); | ||
336 | |||
337 | /* shutdown subsystems */ | ||
338 | tw5864_interrupts_disable(dev); | ||
339 | |||
340 | /* unregister */ | ||
341 | tw5864_video_fini(dev); | ||
342 | |||
343 | /* release resources */ | ||
344 | iounmap(dev->mmio); | ||
345 | release_mem_region(pci_resource_start(pci_dev, 0), | ||
346 | pci_resource_len(pci_dev, 0)); | ||
347 | |||
348 | v4l2_device_unregister(&dev->v4l2_dev); | ||
349 | devm_kfree(&pci_dev->dev, dev); | ||
350 | } | ||
351 | |||
352 | static struct pci_driver tw5864_pci_driver = { | ||
353 | .name = "tw5864", | ||
354 | .id_table = tw5864_pci_tbl, | ||
355 | .probe = tw5864_initdev, | ||
356 | .remove = tw5864_finidev, | ||
357 | }; | ||
358 | |||
359 | module_pci_driver(tw5864_pci_driver); | ||
diff --git a/drivers/media/pci/tw5864/tw5864-h264.c b/drivers/media/pci/tw5864/tw5864-h264.c new file mode 100644 index 000000000000..330d200f52cd --- /dev/null +++ b/drivers/media/pci/tw5864/tw5864-h264.c | |||
@@ -0,0 +1,259 @@ | |||
1 | /* | ||
2 | * TW5864 driver - H.264 headers generation functions | ||
3 | * | ||
4 | * Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/log2.h> | ||
18 | |||
19 | #include "tw5864.h" | ||
20 | |||
21 | static u8 marker[] = { 0x00, 0x00, 0x00, 0x01 }; | ||
22 | |||
23 | /* | ||
24 | * Exponential-Golomb coding functions | ||
25 | * | ||
26 | * These functions are used for generation of H.264 bitstream headers. | ||
27 | * | ||
28 | * This code is derived from tw5864 reference driver by manufacturers, which | ||
29 | * itself apparently was derived from x264 project. | ||
30 | */ | ||
31 | |||
32 | /* Bitstream writing context */ | ||
33 | struct bs { | ||
34 | u8 *buf; /* pointer to buffer beginning */ | ||
35 | u8 *buf_end; /* pointer to buffer end */ | ||
36 | u8 *ptr; /* pointer to current byte in buffer */ | ||
37 | unsigned int bits_left; /* number of available bits in current byte */ | ||
38 | }; | ||
39 | |||
40 | static void bs_init(struct bs *s, void *buf, int size) | ||
41 | { | ||
42 | s->buf = buf; | ||
43 | s->ptr = buf; | ||
44 | s->buf_end = s->ptr + size; | ||
45 | s->bits_left = 8; | ||
46 | } | ||
47 | |||
48 | static int bs_len(struct bs *s) | ||
49 | { | ||
50 | return s->ptr - s->buf; | ||
51 | } | ||
52 | |||
53 | static void bs_write(struct bs *s, int count, u32 bits) | ||
54 | { | ||
55 | if (s->ptr >= s->buf_end - 4) | ||
56 | return; | ||
57 | while (count > 0) { | ||
58 | if (count < 32) | ||
59 | bits &= (1 << count) - 1; | ||
60 | if (count < s->bits_left) { | ||
61 | *s->ptr = (*s->ptr << count) | bits; | ||
62 | s->bits_left -= count; | ||
63 | break; | ||
64 | } | ||
65 | *s->ptr = (*s->ptr << s->bits_left) | | ||
66 | (bits >> (count - s->bits_left)); | ||
67 | count -= s->bits_left; | ||
68 | s->ptr++; | ||
69 | s->bits_left = 8; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | static void bs_write1(struct bs *s, u32 bit) | ||
74 | { | ||
75 | if (s->ptr < s->buf_end) { | ||
76 | *s->ptr <<= 1; | ||
77 | *s->ptr |= bit; | ||
78 | s->bits_left--; | ||
79 | if (s->bits_left == 0) { | ||
80 | s->ptr++; | ||
81 | s->bits_left = 8; | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | |||
86 | static void bs_write_ue(struct bs *s, u32 val) | ||
87 | { | ||
88 | if (val == 0) { | ||
89 | bs_write1(s, 1); | ||
90 | } else { | ||
91 | val++; | ||
92 | bs_write(s, 2 * fls(val) - 1, val); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | static void bs_write_se(struct bs *s, int val) | ||
97 | { | ||
98 | bs_write_ue(s, val <= 0 ? -val * 2 : val * 2 - 1); | ||
99 | } | ||
100 | |||
101 | static void bs_rbsp_trailing(struct bs *s) | ||
102 | { | ||
103 | bs_write1(s, 1); | ||
104 | if (s->bits_left != 8) | ||
105 | bs_write(s, s->bits_left, 0x00); | ||
106 | } | ||
107 | |||
108 | /* H.264 headers generation functions */ | ||
109 | |||
110 | static int tw5864_h264_gen_sps_rbsp(u8 *buf, size_t size, int width, int height) | ||
111 | { | ||
112 | struct bs bs, *s; | ||
113 | |||
114 | s = &bs; | ||
115 | bs_init(s, buf, size); | ||
116 | bs_write(s, 8, 0x42); /* profile_idc, baseline */ | ||
117 | bs_write(s, 1, 1); /* constraint_set0_flag */ | ||
118 | bs_write(s, 1, 1); /* constraint_set1_flag */ | ||
119 | bs_write(s, 1, 0); /* constraint_set2_flag */ | ||
120 | bs_write(s, 5, 0); /* reserved_zero_5bits */ | ||
121 | bs_write(s, 8, 0x1e); /* level_idc */ | ||
122 | bs_write_ue(s, 0); /* seq_parameter_set_id */ | ||
123 | bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4); /* log2_max_frame_num_minus4 */ | ||
124 | bs_write_ue(s, 0); /* pic_order_cnt_type */ | ||
125 | /* log2_max_pic_order_cnt_lsb_minus4 */ | ||
126 | bs_write_ue(s, ilog2(MAX_GOP_SIZE) - 4); | ||
127 | bs_write_ue(s, 1); /* num_ref_frames */ | ||
128 | bs_write(s, 1, 0); /* gaps_in_frame_num_value_allowed_flag */ | ||
129 | bs_write_ue(s, width / 16 - 1); /* pic_width_in_mbs_minus1 */ | ||
130 | bs_write_ue(s, height / 16 - 1); /* pic_height_in_map_units_minus1 */ | ||
131 | bs_write(s, 1, 1); /* frame_mbs_only_flag */ | ||
132 | bs_write(s, 1, 0); /* direct_8x8_inference_flag */ | ||
133 | bs_write(s, 1, 0); /* frame_cropping_flag */ | ||
134 | bs_write(s, 1, 0); /* vui_parameters_present_flag */ | ||
135 | bs_rbsp_trailing(s); | ||
136 | return bs_len(s); | ||
137 | } | ||
138 | |||
139 | static int tw5864_h264_gen_pps_rbsp(u8 *buf, size_t size, int qp) | ||
140 | { | ||
141 | struct bs bs, *s; | ||
142 | |||
143 | s = &bs; | ||
144 | bs_init(s, buf, size); | ||
145 | bs_write_ue(s, 0); /* pic_parameter_set_id */ | ||
146 | bs_write_ue(s, 0); /* seq_parameter_set_id */ | ||
147 | bs_write(s, 1, 0); /* entropy_coding_mode_flag */ | ||
148 | bs_write(s, 1, 0); /* pic_order_present_flag */ | ||
149 | bs_write_ue(s, 0); /* num_slice_groups_minus1 */ | ||
150 | bs_write_ue(s, 0); /* i_num_ref_idx_l0_active_minus1 */ | ||
151 | bs_write_ue(s, 0); /* i_num_ref_idx_l1_active_minus1 */ | ||
152 | bs_write(s, 1, 0); /* weighted_pred_flag */ | ||
153 | bs_write(s, 2, 0); /* weighted_bipred_idc */ | ||
154 | bs_write_se(s, qp - 26); /* pic_init_qp_minus26 */ | ||
155 | bs_write_se(s, qp - 26); /* pic_init_qs_minus26 */ | ||
156 | bs_write_se(s, 0); /* chroma_qp_index_offset */ | ||
157 | bs_write(s, 1, 0); /* deblocking_filter_control_present_flag */ | ||
158 | bs_write(s, 1, 0); /* constrained_intra_pred_flag */ | ||
159 | bs_write(s, 1, 0); /* redundant_pic_cnt_present_flag */ | ||
160 | bs_rbsp_trailing(s); | ||
161 | return bs_len(s); | ||
162 | } | ||
163 | |||
164 | static int tw5864_h264_gen_slice_head(u8 *buf, size_t size, | ||
165 | unsigned int idr_pic_id, | ||
166 | unsigned int frame_gop_seqno, | ||
167 | int *tail_nb_bits, u8 *tail) | ||
168 | { | ||
169 | struct bs bs, *s; | ||
170 | int is_i_frame = frame_gop_seqno == 0; | ||
171 | |||
172 | s = &bs; | ||
173 | bs_init(s, buf, size); | ||
174 | bs_write_ue(s, 0); /* first_mb_in_slice */ | ||
175 | bs_write_ue(s, is_i_frame ? 2 : 5); /* slice_type - I or P */ | ||
176 | bs_write_ue(s, 0); /* pic_parameter_set_id */ | ||
177 | bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno); /* frame_num */ | ||
178 | if (is_i_frame) | ||
179 | bs_write_ue(s, idr_pic_id); | ||
180 | |||
181 | /* pic_order_cnt_lsb */ | ||
182 | bs_write(s, ilog2(MAX_GOP_SIZE), frame_gop_seqno); | ||
183 | |||
184 | if (is_i_frame) { | ||
185 | bs_write1(s, 0); /* no_output_of_prior_pics_flag */ | ||
186 | bs_write1(s, 0); /* long_term_reference_flag */ | ||
187 | } else { | ||
188 | bs_write1(s, 0); /* num_ref_idx_active_override_flag */ | ||
189 | bs_write1(s, 0); /* ref_pic_list_reordering_flag_l0 */ | ||
190 | bs_write1(s, 0); /* adaptive_ref_pic_marking_mode_flag */ | ||
191 | } | ||
192 | |||
193 | bs_write_se(s, 0); /* slice_qp_delta */ | ||
194 | |||
195 | if (s->bits_left != 8) { | ||
196 | *tail = ((s->ptr[0]) << s->bits_left); | ||
197 | *tail_nb_bits = 8 - s->bits_left; | ||
198 | } else { | ||
199 | *tail = 0; | ||
200 | *tail_nb_bits = 0; | ||
201 | } | ||
202 | |||
203 | return bs_len(s); | ||
204 | } | ||
205 | |||
206 | void tw5864_h264_put_stream_header(u8 **buf, size_t *space_left, int qp, | ||
207 | int width, int height) | ||
208 | { | ||
209 | int nal_len; | ||
210 | |||
211 | /* SPS */ | ||
212 | memcpy(*buf, marker, sizeof(marker)); | ||
213 | *buf += 4; | ||
214 | *space_left -= 4; | ||
215 | |||
216 | **buf = 0x67; /* SPS NAL header */ | ||
217 | *buf += 1; | ||
218 | *space_left -= 1; | ||
219 | |||
220 | nal_len = tw5864_h264_gen_sps_rbsp(*buf, *space_left, width, height); | ||
221 | *buf += nal_len; | ||
222 | *space_left -= nal_len; | ||
223 | |||
224 | /* PPS */ | ||
225 | memcpy(*buf, marker, sizeof(marker)); | ||
226 | *buf += 4; | ||
227 | *space_left -= 4; | ||
228 | |||
229 | **buf = 0x68; /* PPS NAL header */ | ||
230 | *buf += 1; | ||
231 | *space_left -= 1; | ||
232 | |||
233 | nal_len = tw5864_h264_gen_pps_rbsp(*buf, *space_left, qp); | ||
234 | *buf += nal_len; | ||
235 | *space_left -= nal_len; | ||
236 | } | ||
237 | |||
238 | void tw5864_h264_put_slice_header(u8 **buf, size_t *space_left, | ||
239 | unsigned int idr_pic_id, | ||
240 | unsigned int frame_gop_seqno, | ||
241 | int *tail_nb_bits, u8 *tail) | ||
242 | { | ||
243 | int nal_len; | ||
244 | |||
245 | memcpy(*buf, marker, sizeof(marker)); | ||
246 | *buf += 4; | ||
247 | *space_left -= 4; | ||
248 | |||
249 | /* Frame NAL header */ | ||
250 | **buf = (frame_gop_seqno == 0) ? 0x25 : 0x21; | ||
251 | *buf += 1; | ||
252 | *space_left -= 1; | ||
253 | |||
254 | nal_len = tw5864_h264_gen_slice_head(*buf, *space_left, idr_pic_id, | ||
255 | frame_gop_seqno, tail_nb_bits, | ||
256 | tail); | ||
257 | *buf += nal_len; | ||
258 | *space_left -= nal_len; | ||
259 | } | ||
diff --git a/drivers/media/pci/tw5864/tw5864-reg.h b/drivers/media/pci/tw5864/tw5864-reg.h new file mode 100644 index 000000000000..92a1b077ef8a --- /dev/null +++ b/drivers/media/pci/tw5864/tw5864-reg.h | |||
@@ -0,0 +1,2133 @@ | |||
1 | /* | ||
2 | * TW5864 driver - registers description | ||
3 | * | ||
4 | * Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | /* According to TW5864_datasheet_0.6d.pdf, tw5864b1-ds.pdf */ | ||
18 | |||
19 | /* Register Description - Direct Map Space */ | ||
20 | /* 0x0000 ~ 0x1ffc - H264 Register Map */ | ||
21 | /* [15:0] The Version register for H264 core (Read Only) */ | ||
22 | #define TW5864_H264REV 0x0000 | ||
23 | |||
24 | #define TW5864_EMU 0x0004 | ||
25 | /* Define controls in register TW5864_EMU */ | ||
26 | /* DDR controller enabled */ | ||
27 | #define TW5864_EMU_EN_DDR BIT(0) | ||
28 | /* Enable bit for Inter module */ | ||
29 | #define TW5864_EMU_EN_ME BIT(1) | ||
30 | /* Enable bit for Sensor Interface module */ | ||
31 | #define TW5864_EMU_EN_SEN BIT(2) | ||
32 | /* Enable bit for Host Burst Access */ | ||
33 | #define TW5864_EMU_EN_BHOST BIT(3) | ||
34 | /* Enable bit for Loop Filter module */ | ||
35 | #define TW5864_EMU_EN_LPF BIT(4) | ||
36 | /* Enable bit for PLBK module */ | ||
37 | #define TW5864_EMU_EN_PLBK BIT(5) | ||
38 | /* | ||
39 | * Video Frame mapping in DDR | ||
40 | * 00 CIF | ||
41 | * 01 D1 | ||
42 | * 10 Reserved | ||
43 | * 11 Reserved | ||
44 | * | ||
45 | */ | ||
46 | #define TW5864_DSP_FRAME_TYPE (3 << 6) | ||
47 | #define TW5864_DSP_FRAME_TYPE_D1 BIT(6) | ||
48 | |||
49 | #define TW5864_UNDECLARED_H264REV_PART2 0x0008 | ||
50 | |||
51 | #define TW5864_SLICE 0x000c | ||
52 | /* Define controls in register TW5864_SLICE */ | ||
53 | /* VLC Slice end flag */ | ||
54 | #define TW5864_VLC_SLICE_END BIT(0) | ||
55 | /* Master Slice End Flag */ | ||
56 | #define TW5864_MAS_SLICE_END BIT(4) | ||
57 | /* Host to start a new slice Address */ | ||
58 | #define TW5864_START_NSLICE BIT(15) | ||
59 | |||
60 | /* | ||
61 | * [15:0] Two bit for each channel (channel 0 ~ 7). Each two bits are the buffer | ||
62 | * pointer for the last encoded frame of the corresponding channel. | ||
63 | */ | ||
64 | #define TW5864_ENC_BUF_PTR_REC1 0x0010 | ||
65 | |||
66 | /* [5:0] DSP_MB_QP and [15:10] DSP_LPF_OFFSET */ | ||
67 | #define TW5864_DSP_QP 0x0018 | ||
68 | /* Define controls in register TW5864_DSP_QP */ | ||
69 | /* [5:0] H264 QP Value for codec */ | ||
70 | #define TW5864_DSP_MB_QP 0x003f | ||
71 | /* | ||
72 | * [15:10] H264 LPF_OFFSET Address | ||
73 | * (Default 0) | ||
74 | */ | ||
75 | #define TW5864_DSP_LPF_OFFSET 0xfc00 | ||
76 | |||
77 | #define TW5864_DSP_CODEC 0x001c | ||
78 | /* Define controls in register TW5864_DSP_CODEC */ | ||
79 | /* | ||
80 | * 0: Encode (TW5864 Default) | ||
81 | * 1: Decode | ||
82 | */ | ||
83 | #define TW5864_DSP_CODEC_MODE BIT(0) | ||
84 | /* | ||
85 | * 0->3 4 VLC data buffer in DDR (1M each) | ||
86 | * 0->7 8 VLC data buffer in DDR (512k each) | ||
87 | */ | ||
88 | #define TW5864_VLC_BUF_ID (7 << 2) | ||
89 | /* | ||
90 | * 0 4CIF in 1 MB | ||
91 | * 1 1CIF in 1 MB | ||
92 | */ | ||
93 | #define TW5864_CIF_MAP_MD BIT(6) | ||
94 | /* | ||
95 | * 0 2 falf D1 in 1 MB | ||
96 | * 1 1 half D1 in 1 MB | ||
97 | */ | ||
98 | #define TW5864_HD1_MAP_MD BIT(7) | ||
99 | /* VLC Stream valid */ | ||
100 | #define TW5864_VLC_VLD BIT(8) | ||
101 | /* MV Vector Valid */ | ||
102 | #define TW5864_MV_VECT_VLD BIT(9) | ||
103 | /* MV Flag Valid */ | ||
104 | #define TW5864_MV_FLAG_VLD BIT(10) | ||
105 | |||
106 | #define TW5864_DSP_SEN 0x0020 | ||
107 | /* Define controls in register TW5864_DSP_SEN */ | ||
108 | /* Org Buffer Base for Luma (default 0) */ | ||
109 | #define TW5864_DSP_SEN_PIC_LU 0x000f | ||
110 | /* Org Buffer Base for Chroma (default 4) */ | ||
111 | #define TW5864_DSP_SEN_PIC_CHM 0x00f0 | ||
112 | /* Maximum Number of Buffers (default 4) */ | ||
113 | #define TW5864_DSP_SEN_PIC_MAX 0x0700 | ||
114 | /* | ||
115 | * Original Frame D1 or HD1 switch | ||
116 | * (Default 0) | ||
117 | */ | ||
118 | #define TW5864_DSP_SEN_HFULL 0x1000 | ||
119 | |||
120 | #define TW5864_DSP_REF_PIC 0x0024 | ||
121 | /* Define controls in register TW5864_DSP_REF_PIC */ | ||
122 | /* Ref Buffer Base for Luma (default 0) */ | ||
123 | #define TW5864_DSP_REF_PIC_LU 0x000f | ||
124 | /* Ref Buffer Base for Chroma (default 4) */ | ||
125 | #define TW5864_DSP_REF_PIC_CHM 0x00f0 | ||
126 | /* Maximum Number of Buffers (default 4) */ | ||
127 | #define TW5864_DSP_REF_PIC_MAX 0x0700 | ||
128 | |||
129 | /* [15:0] SEN_EN_CH[n] SENIF original frame capture enable for each channel */ | ||
130 | #define TW5864_SEN_EN_CH 0x0028 | ||
131 | |||
132 | #define TW5864_DSP 0x002c | ||
133 | /* Define controls in register TW5864_DSP */ | ||
134 | /* The ID for channel selected for encoding operation */ | ||
135 | #define TW5864_DSP_ENC_CHN 0x000f | ||
136 | /* See DSP_MB_DELAY below */ | ||
137 | #define TW5864_DSP_MB_WAIT 0x0010 | ||
138 | /* | ||
139 | * DSP Chroma Switch | ||
140 | * 0 DDRB | ||
141 | * 1 DDRA | ||
142 | */ | ||
143 | #define TW5864_DSP_CHROM_SW 0x0020 | ||
144 | /* VLC Flow Control: 1 for enable */ | ||
145 | #define TW5864_DSP_FLW_CNTL 0x0040 | ||
146 | /* | ||
147 | * If DSP_MB_WAIT == 0, MB delay is DSP_MB_DELAY * 16 | ||
148 | * If DSP_MB_DELAY == 1, MB delay is DSP_MB_DELAY * 128 | ||
149 | */ | ||
150 | #define TW5864_DSP_MB_DELAY 0x0f00 | ||
151 | |||
152 | #define TW5864_DDR 0x0030 | ||
153 | /* Define controls in register TW5864_DDR */ | ||
154 | /* DDR Single Access Page Number */ | ||
155 | #define TW5864_DDR_PAGE_CNTL 0x00ff | ||
156 | /* DDR-DPR Burst Read Enable */ | ||
157 | #define TW5864_DDR_BRST_EN BIT(13) | ||
158 | /* | ||
159 | * DDR A/B Select as HOST access | ||
160 | * 0 Select DDRA | ||
161 | * 1 Select DDRB | ||
162 | */ | ||
163 | #define TW5864_DDR_AB_SEL BIT(14) | ||
164 | /* | ||
165 | * DDR Access Mode Select | ||
166 | * 0 Single R/W Access (Host <-> DDR) | ||
167 | * 1 Burst R/W Access (Host <-> DPR) | ||
168 | */ | ||
169 | #define TW5864_DDR_MODE BIT(15) | ||
170 | |||
171 | /* The original frame capture pointer. Two bits for each channel */ | ||
172 | /* SENIF_ORG_FRM_PTR [15:0] */ | ||
173 | #define TW5864_SENIF_ORG_FRM_PTR1 0x0038 | ||
174 | /* SENIF_ORG_FRM_PTR [31:16] */ | ||
175 | #define TW5864_SENIF_ORG_FRM_PTR2 0x003c | ||
176 | |||
177 | #define TW5864_DSP_SEN_MODE 0x0040 | ||
178 | /* Define controls in register TW5864_DSP_SEN_MODE */ | ||
179 | #define TW5864_DSP_SEN_MODE_CH0 0x000f | ||
180 | #define TW5864_DSP_SEN_MODE_CH1 0x00f0 | ||
181 | |||
182 | /* | ||
183 | * [15:0]: ENC_BUF_PTR_REC[31:16] Two bit for each channel (channel 8 ~ 15). | ||
184 | * Each two bits are the buffer pointer for the last encoded frame of a channel | ||
185 | */ | ||
186 | #define TW5864_ENC_BUF_PTR_REC2 0x004c | ||
187 | |||
188 | /* Current MV Flag Status Pointer for Channel n. (Read only) */ | ||
189 | /* | ||
190 | * [1:0] CH0_MV_PTR, ..., [15:14] CH7_MV_PTR | ||
191 | */ | ||
192 | #define TW5864_CH_MV_PTR1 0x0060 | ||
193 | /* | ||
194 | * [1:0] CH8_MV_PTR, ..., [15:14] CH15_MV_PTR | ||
195 | */ | ||
196 | #define TW5864_CH_MV_PTR2 0x0064 | ||
197 | |||
198 | /* | ||
199 | * [15:0] Reset Current MV Flag Status Pointer for Channel n (one bit each) | ||
200 | */ | ||
201 | #define TW5864_RST_MV_PTR 0x0068 | ||
202 | #define TW5864_INTERLACING 0x0200 | ||
203 | /* Define controls in register TW5864_INTERLACING */ | ||
204 | /* | ||
205 | * Inter_Mode Start. 2-nd bit? A guess. Missing in datasheet. Without this bit | ||
206 | * set, the output video is interlaced (stripy). | ||
207 | */ | ||
208 | #define TW5864_DSP_INTER_ST BIT(1) | ||
209 | /* Deinterlacer Enable */ | ||
210 | #define TW5864_DI_EN BIT(2) | ||
211 | /* | ||
212 | * De-interlacer Mode | ||
213 | * 1 Shuffled frame | ||
214 | * 0 Normal Un-Shuffled Frame | ||
215 | */ | ||
216 | #define TW5864_DI_MD BIT(3) | ||
217 | /* | ||
218 | * Down scale original frame in X direction | ||
219 | * 11: Un-used | ||
220 | * 10: down-sample to 1/4 | ||
221 | * 01: down-sample to 1/2 | ||
222 | * 00: down-sample disabled | ||
223 | */ | ||
224 | #define TW5864_DSP_DWN_X (3 << 4) | ||
225 | /* | ||
226 | * Down scale original frame in Y direction | ||
227 | * 11: Un-used | ||
228 | * 10: down-sample to 1/4 | ||
229 | * 01: down-sample to 1/2 | ||
230 | * 00: down-sample disabled | ||
231 | */ | ||
232 | #define TW5864_DSP_DWN_Y (3 << 6) | ||
233 | /* | ||
234 | * 1 Dual Stream | ||
235 | * 0 Single Stream | ||
236 | */ | ||
237 | #define TW5864_DUAL_STR BIT(8) | ||
238 | |||
239 | #define TW5864_DSP_REF 0x0204 | ||
240 | /* Define controls in register TW5864_DSP_REF */ | ||
241 | /* Number of reference frame (Default 1 for TW5864B) */ | ||
242 | #define TW5864_DSP_REF_FRM 0x000f | ||
243 | /* Window size */ | ||
244 | #define TW5864_DSP_WIN_SIZE 0x02f0 | ||
245 | |||
246 | #define TW5864_DSP_SKIP 0x0208 | ||
247 | /* Define controls in register TW5864_DSP_SKIP */ | ||
248 | /* | ||
249 | * Skip Offset Enable bit | ||
250 | * 0 DSP_SKIP_OFFSET value is not used (default 8) | ||
251 | * 1 DSP_SKIP_OFFSET value is used in HW | ||
252 | */ | ||
253 | #define TW5864_DSP_SKIP_OFEN 0x0080 | ||
254 | /* Skip mode cost offset (default 8) */ | ||
255 | #define TW5864_DSP_SKIP_OFFSET 0x007f | ||
256 | |||
257 | #define TW5864_MOTION_SEARCH_ETC 0x020c | ||
258 | /* Define controls in register TW5864_MOTION_SEARCH_ETC */ | ||
259 | /* Enable quarter pel search mode */ | ||
260 | #define TW5864_QPEL_EN BIT(0) | ||
261 | /* Enable half pel search mode */ | ||
262 | #define TW5864_HPEL_EN BIT(1) | ||
263 | /* Enable motion search mode */ | ||
264 | #define TW5864_ME_EN BIT(2) | ||
265 | /* Enable Intra mode */ | ||
266 | #define TW5864_INTRA_EN BIT(3) | ||
267 | /* Enable Skip Mode */ | ||
268 | #define TW5864_SKIP_EN BIT(4) | ||
269 | /* Search Option (Default 2"b01) */ | ||
270 | #define TW5864_SRCH_OPT (3 << 5) | ||
271 | |||
272 | #define TW5864_DSP_ENC_REC 0x0210 | ||
273 | /* Define controls in register TW5864_DSP_ENC_REC */ | ||
274 | /* Reference Buffer Pointer for encoding */ | ||
275 | #define TW5864_DSP_ENC_REF_PTR 0x0007 | ||
276 | /* Reconstruct Buffer pointer */ | ||
277 | #define TW5864_DSP_REC_BUF_PTR 0x7000 | ||
278 | |||
279 | /* [15:0] Lambda Value for H264 */ | ||
280 | #define TW5864_DSP_REF_MVP_LAMBDA 0x0214 | ||
281 | |||
282 | #define TW5864_DSP_PIC_MAX_MB 0x0218 | ||
283 | /* Define controls in register TW5864_DSP_PIC_MAX_MB */ | ||
284 | /* The MB number in Y direction for a frame */ | ||
285 | #define TW5864_DSP_PIC_MAX_MB_Y 0x007f | ||
286 | /* The MB number in X direction for a frame */ | ||
287 | #define TW5864_DSP_PIC_MAX_MB_X 0x7f00 | ||
288 | |||
289 | /* The original frame pointer for encoding */ | ||
290 | #define TW5864_DSP_ENC_ORG_PTR_REG 0x021c | ||
291 | /* Mask to use with TW5864_DSP_ENC_ORG_PTR */ | ||
292 | #define TW5864_DSP_ENC_ORG_PTR_MASK 0x7000 | ||
293 | /* Number of bits to shift with TW5864_DSP_ENC_ORG_PTR */ | ||
294 | #define TW5864_DSP_ENC_ORG_PTR_SHIFT 12 | ||
295 | |||
296 | /* DDR base address of OSD rectangle attribute data */ | ||
297 | #define TW5864_DSP_OSD_ATTRI_BASE 0x0220 | ||
298 | /* OSD enable bit for each channel */ | ||
299 | #define TW5864_DSP_OSD_ENABLE 0x0228 | ||
300 | |||
301 | /* 0x0280 ~ 0x029c – Motion Vector for 1st 4x4 Block, e.g., 80 (X), 84 (Y) */ | ||
302 | #define TW5864_ME_MV_VEC1 0x0280 | ||
303 | /* 0x02a0 ~ 0x02bc – Motion Vector for 2nd 4x4 Block, e.g., A0 (X), A4 (Y) */ | ||
304 | #define TW5864_ME_MV_VEC2 0x02a0 | ||
305 | /* 0x02c0 ~ 0x02dc – Motion Vector for 3rd 4x4 Block, e.g., C0 (X), C4 (Y) */ | ||
306 | #define TW5864_ME_MV_VEC3 0x02c0 | ||
307 | /* 0x02e0 ~ 0x02fc – Motion Vector for 4th 4x4 Block, e.g., E0 (X), E4 (Y) */ | ||
308 | #define TW5864_ME_MV_VEC4 0x02e0 | ||
309 | |||
310 | /* | ||
311 | * [5:0] | ||
312 | * if (intra16x16_cost < (intra4x4_cost+dsp_i4x4_offset)) | ||
313 | * Intra_mode = intra16x16_mode | ||
314 | * Else | ||
315 | * Intra_mode = intra4x4_mode | ||
316 | */ | ||
317 | #define TW5864_DSP_I4x4_OFFSET 0x040c | ||
318 | |||
319 | /* | ||
320 | * [6:4] | ||
321 | * 0x5 Only 4x4 | ||
322 | * 0x6 Only 16x16 | ||
323 | * 0x7 16x16 & 4x4 | ||
324 | */ | ||
325 | #define TW5864_DSP_INTRA_MODE 0x0410 | ||
326 | #define TW5864_DSP_INTRA_MODE_SHIFT 4 | ||
327 | #define TW5864_DSP_INTRA_MODE_MASK (7 << 4) | ||
328 | #define TW5864_DSP_INTRA_MODE_4x4 0x5 | ||
329 | #define TW5864_DSP_INTRA_MODE_16x16 0x6 | ||
330 | #define TW5864_DSP_INTRA_MODE_4x4_AND_16x16 0x7 | ||
331 | /* | ||
332 | * [5:0] WEIGHT Factor for I4x4 cost calculation (QP dependent) | ||
333 | */ | ||
334 | #define TW5864_DSP_I4x4_WEIGHT 0x0414 | ||
335 | |||
336 | /* | ||
337 | * [7:0] Offset used to affect Intra/ME model decision | ||
338 | * If (me_cost < intra_cost + dsp_resid_mode_offset) | ||
339 | * Pred_Mode = me_mode | ||
340 | * Else | ||
341 | * Pred_mode = intra_mode | ||
342 | */ | ||
343 | #define TW5864_DSP_RESID_MODE_OFFSET 0x0604 | ||
344 | |||
345 | /* 0x0800 ~ 0x09ff - Quantization TABLE Values */ | ||
346 | #define TW5864_QUAN_TAB 0x0800 | ||
347 | |||
348 | /* Valid channel value [0; f], frame value [0; 3] */ | ||
349 | #define TW5864_RT_CNTR_CH_FRM(channel, frame) \ | ||
350 | (0x0c00 | (channel << 4) | (frame << 2)) | ||
351 | |||
352 | #define TW5864_FRAME_BUS1 0x0d00 | ||
353 | /* | ||
354 | * 1 Progressive in part A in bus n | ||
355 | * 0 Interlaced in part A in bus n | ||
356 | */ | ||
357 | #define TW5864_PROG_A BIT(0) | ||
358 | /* | ||
359 | * 1 Progressive in part B in bus n | ||
360 | * 0 Interlaced in part B in bus n | ||
361 | */ | ||
362 | #define TW5864_PROG_B BIT(1) | ||
363 | /* | ||
364 | * 1 Frame Mode in bus n | ||
365 | * 0 Field Mode in bus n | ||
366 | */ | ||
367 | #define TW5864_FRAME BIT(2) | ||
368 | /* | ||
369 | * 0 4CIF in bus n | ||
370 | * 1 1D1 + 4 CIF in bus n | ||
371 | * 2 2D1 in bus n | ||
372 | */ | ||
373 | #define TW5864_BUS_D1 (3 << 3) | ||
374 | /* Bus 1 goes in TW5864_FRAME_BUS1 in [4:0] */ | ||
375 | /* Bus 2 goes in TW5864_FRAME_BUS1 in [12:8] */ | ||
376 | #define TW5864_FRAME_BUS2 0x0d04 | ||
377 | /* Bus 3 goes in TW5864_FRAME_BUS2 in [4:0] */ | ||
378 | /* Bus 4 goes in TW5864_FRAME_BUS2 in [12:8] */ | ||
379 | |||
380 | /* [15:0] Horizontal Mirror for channel n */ | ||
381 | #define TW5864_SENIF_HOR_MIR 0x0d08 | ||
382 | /* [15:0] Vertical Mirror for channel n */ | ||
383 | #define TW5864_SENIF_VER_MIR 0x0d0c | ||
384 | |||
385 | /* | ||
386 | * FRAME_WIDTH_BUSn_A | ||
387 | * 0x15f: 4 CIF | ||
388 | * 0x2cf: 1 D1 + 3 CIF | ||
389 | * 0x2cf: 2 D1 | ||
390 | * FRAME_WIDTH_BUSn_B | ||
391 | * 0x15f: 4 CIF | ||
392 | * 0x2cf: 1 D1 + 3 CIF | ||
393 | * 0x2cf: 2 D1 | ||
394 | * FRAME_HEIGHT_BUSn_A | ||
395 | * 0x11f: 4CIF (PAL) | ||
396 | * 0x23f: 1D1 + 3CIF (PAL) | ||
397 | * 0x23f: 2 D1 (PAL) | ||
398 | * 0x0ef: 4CIF (NTSC) | ||
399 | * 0x1df: 1D1 + 3CIF (NTSC) | ||
400 | * 0x1df: 2 D1 (NTSC) | ||
401 | * FRAME_HEIGHT_BUSn_B | ||
402 | * 0x11f: 4CIF (PAL) | ||
403 | * 0x23f: 1D1 + 3CIF (PAL) | ||
404 | * 0x23f: 2 D1 (PAL) | ||
405 | * 0x0ef: 4CIF (NTSC) | ||
406 | * 0x1df: 1D1 + 3CIF (NTSC) | ||
407 | * 0x1df: 2 D1 (NTSC) | ||
408 | */ | ||
409 | #define TW5864_FRAME_WIDTH_BUS_A(bus) (0x0d10 + 0x0010 * bus) | ||
410 | #define TW5864_FRAME_WIDTH_BUS_B(bus) (0x0d14 + 0x0010 * bus) | ||
411 | #define TW5864_FRAME_HEIGHT_BUS_A(bus) (0x0d18 + 0x0010 * bus) | ||
412 | #define TW5864_FRAME_HEIGHT_BUS_B(bus) (0x0d1c + 0x0010 * bus) | ||
413 | |||
414 | /* | ||
415 | * 1: the bus mapped Channel n Full D1 | ||
416 | * 0: the bus mapped Channel n Half D1 | ||
417 | */ | ||
418 | #define TW5864_FULL_HALF_FLAG 0x0d50 | ||
419 | |||
420 | /* | ||
421 | * 0 The bus mapped Channel select partA Mode | ||
422 | * 1 The bus mapped Channel select partB Mode | ||
423 | */ | ||
424 | #define TW5864_FULL_HALF_MODE_SEL 0x0d54 | ||
425 | |||
426 | #define TW5864_VLC 0x1000 | ||
427 | /* Define controls in register TW5864_VLC */ | ||
428 | /* QP Value used by H264 CAVLC */ | ||
429 | #define TW5864_VLC_SLICE_QP 0x003f | ||
430 | /* | ||
431 | * Swap byte order of VLC stream in d-word. | ||
432 | * 1 Normal (VLC output= [31:0]) | ||
433 | * 0 Swap (VLC output={[23:16],[31:24],[7:0], [15:8]}) | ||
434 | */ | ||
435 | #define TW5864_VLC_BYTE_SWP BIT(6) | ||
436 | /* Enable Adding 03 circuit for VLC stream */ | ||
437 | #define TW5864_VLC_ADD03_EN BIT(7) | ||
438 | /* Number of bit for VLC bit Align */ | ||
439 | #define TW5864_VLC_BIT_ALIGN_SHIFT 8 | ||
440 | #define TW5864_VLC_BIT_ALIGN_MASK (0x1f << 8) | ||
441 | /* | ||
442 | * Synchronous Interface select for VLC Stream | ||
443 | * 1 CDC_VLCS_MAS read VLC stream | ||
444 | * 0 CPU read VLC stream | ||
445 | */ | ||
446 | #define TW5864_VLC_INF_SEL BIT(13) | ||
447 | /* Enable VLC overflow control */ | ||
448 | #define TW5864_VLC_OVFL_CNTL BIT(14) | ||
449 | /* | ||
450 | * 1 PCI Master Mode | ||
451 | * 0 Non PCI Master Mode | ||
452 | */ | ||
453 | #define TW5864_VLC_PCI_SEL BIT(15) | ||
454 | /* | ||
455 | * 0 Enable Adding 03 to VLC header and stream | ||
456 | * 1 Disable Adding 03 to VLC header of "00000001" | ||
457 | */ | ||
458 | #define TW5864_VLC_A03_DISAB BIT(16) | ||
459 | /* | ||
460 | * Status of VLC stream in DDR (one bit for each buffer) | ||
461 | * 1 VLC is ready in buffer n (HW set) | ||
462 | * 0 VLC is not ready in buffer n (SW clear) | ||
463 | */ | ||
464 | #define TW5864_VLC_BUF_RDY_SHIFT 24 | ||
465 | #define TW5864_VLC_BUF_RDY_MASK (0xff << 24) | ||
466 | |||
467 | /* Total number of bit in the slice */ | ||
468 | #define TW5864_SLICE_TOTAL_BIT 0x1004 | ||
469 | /* Total number of bit in the residue */ | ||
470 | #define TW5864_RES_TOTAL_BIT 0x1008 | ||
471 | |||
472 | #define TW5864_VLC_BUF 0x100c | ||
473 | /* Define controls in register TW5864_VLC_BUF */ | ||
474 | /* VLC BK0 full status, write ‘1’ to clear */ | ||
475 | #define TW5864_VLC_BK0_FULL BIT(0) | ||
476 | /* VLC BK1 full status, write ‘1’ to clear */ | ||
477 | #define TW5864_VLC_BK1_FULL BIT(1) | ||
478 | /* VLC end slice status, write ‘1’ to clear */ | ||
479 | #define TW5864_VLC_END_SLICE BIT(2) | ||
480 | /* VLC Buffer overflow status, write ‘1’ to clear */ | ||
481 | #define TW5864_DSP_RD_OF BIT(3) | ||
482 | /* VLC string length in either buffer 0 or 1 at end of frame */ | ||
483 | #define TW5864_VLC_STREAM_LEN_SHIFT 4 | ||
484 | #define TW5864_VLC_STREAM_LEN_MASK (0x1ff << 4) | ||
485 | |||
486 | /* [15:0] Total coefficient number in a frame */ | ||
487 | #define TW5864_TOTAL_COEF_NO 0x1010 | ||
488 | /* [0] VLC Encoder Interrupt. Write ‘1’ to clear */ | ||
489 | #define TW5864_VLC_DSP_INTR 0x1014 | ||
490 | /* [31:0] VLC stream CRC checksum */ | ||
491 | #define TW5864_VLC_STREAM_CRC 0x1018 | ||
492 | |||
493 | #define TW5864_VLC_RD 0x101c | ||
494 | /* Define controls in register TW5864_VLC_RD */ | ||
495 | /* | ||
496 | * 1 Read VLC lookup Memory | ||
497 | * 0 Read VLC Stream Memory | ||
498 | */ | ||
499 | #define TW5864_VLC_RD_MEM BIT(0) | ||
500 | /* | ||
501 | * 1 Read VLC Stream Memory in burst mode | ||
502 | * 0 Read VLC Stream Memory in single mode | ||
503 | */ | ||
504 | #define TW5864_VLC_RD_BRST BIT(1) | ||
505 | |||
506 | /* 0x2000 ~ 0x2ffc -- H264 Stream Memory Map */ | ||
507 | /* | ||
508 | * A word is 4 bytes. I.e., | ||
509 | * VLC_STREAM_MEM[0] address: 0x2000 | ||
510 | * VLC_STREAM_MEM[1] address: 0x2004 | ||
511 | * ... | ||
512 | * VLC_STREAM_MEM[3FF] address: 0x2ffc | ||
513 | */ | ||
514 | #define TW5864_VLC_STREAM_MEM_START 0x2000 | ||
515 | #define TW5864_VLC_STREAM_MEM_MAX_OFFSET 0x3ff | ||
516 | #define TW5864_VLC_STREAM_MEM(offset) (TW5864_VLC_STREAM_MEM_START + 4 * offset) | ||
517 | |||
518 | /* 0x4000 ~ 0x4ffc -- Audio Register Map */ | ||
519 | /* [31:0] config 1ms cnt = Realtime clk/1000 */ | ||
520 | #define TW5864_CFG_1MS_CNT 0x4000 | ||
521 | |||
522 | #define TW5864_ADPCM 0x4004 | ||
523 | /* Define controls in register TW5864_ADPCM */ | ||
524 | /* ADPCM decoder enable */ | ||
525 | #define TW5864_ADPCM_DEC BIT(0) | ||
526 | /* ADPCM input data enable */ | ||
527 | #define TW5864_ADPCM_IN_DATA BIT(1) | ||
528 | /* ADPCM encoder enable */ | ||
529 | #define TW5864_ADPCM_ENC BIT(2) | ||
530 | |||
531 | #define TW5864_AUD 0x4008 | ||
532 | /* Define controls in register TW5864_AUD */ | ||
533 | /* Record path PCM Audio enable bit for each channel */ | ||
534 | #define TW5864_AUD_ORG_CH_EN 0x00ff | ||
535 | /* Speaker path PCM Audio Enable */ | ||
536 | #define TW5864_SPK_ORG_EN BIT(16) | ||
537 | /* | ||
538 | * 0 16bit | ||
539 | * 1 8bit | ||
540 | */ | ||
541 | #define TW5864_AD_BIT_MODE BIT(17) | ||
542 | #define TW5864_AUD_TYPE_SHIFT 18 | ||
543 | /* | ||
544 | * 0 PCM | ||
545 | * 3 ADPCM | ||
546 | */ | ||
547 | #define TW5864_AUD_TYPE (0xf << 18) | ||
548 | #define TW5864_AUD_SAMPLE_RATE_SHIFT 22 | ||
549 | /* | ||
550 | * 0 8K | ||
551 | * 1 16K | ||
552 | */ | ||
553 | #define TW5864_AUD_SAMPLE_RATE (3 << 22) | ||
554 | /* Channel ID used to select audio channel (0 to 16) for loopback */ | ||
555 | #define TW5864_TESTLOOP_CHID_SHIFT 24 | ||
556 | #define TW5864_TESTLOOP_CHID (0x1f << 24) | ||
557 | /* Enable AD Loopback Test */ | ||
558 | #define TW5864_TEST_ADLOOP_EN BIT(30) | ||
559 | /* | ||
560 | * 0 Asynchronous Mode or PCI target mode | ||
561 | * 1 PCI Initiator Mode | ||
562 | */ | ||
563 | #define TW5864_AUD_MODE BIT(31) | ||
564 | |||
565 | #define TW5864_AUD_ADPCM 0x400c | ||
566 | /* Define controls in register TW5864_AUD_ADPCM */ | ||
567 | /* Record path ADPCM audio channel enable, one bit for each */ | ||
568 | #define TW5864_AUD_ADPCM_CH_EN 0x00ff | ||
569 | /* Speaker path ADPCM audio channel enable */ | ||
570 | #define TW5864_SPK_ADPCM_EN BIT(16) | ||
571 | |||
572 | #define TW5864_PC_BLOCK_ADPCM_RD_NO 0x4018 | ||
573 | #define TW5864_PC_BLOCK_ADPCM_RD_NO_MASK 0x1f | ||
574 | |||
575 | /* | ||
576 | * For ADPCM_ENC_WR_PTR, ADPCM_ENC_RD_PTR (see below): | ||
577 | * Bit[2:0] ch0 | ||
578 | * Bit[5:3] ch1 | ||
579 | * Bit[8:6] ch2 | ||
580 | * Bit[11:9] ch3 | ||
581 | * Bit[14:12] ch4 | ||
582 | * Bit[17:15] ch5 | ||
583 | * Bit[20:18] ch6 | ||
584 | * Bit[23:21] ch7 | ||
585 | * Bit[26:24] ch8 | ||
586 | * Bit[29:27] ch9 | ||
587 | * Bit[32:30] ch10 | ||
588 | * Bit[35:33] ch11 | ||
589 | * Bit[38:36] ch12 | ||
590 | * Bit[41:39] ch13 | ||
591 | * Bit[44:42] ch14 | ||
592 | * Bit[47:45] ch15 | ||
593 | * Bit[50:48] ch16 | ||
594 | */ | ||
595 | #define TW5864_ADPCM_ENC_XX_MASK 0x3fff | ||
596 | #define TW5864_ADPCM_ENC_XX_PTR2_SHIFT 30 | ||
597 | /* ADPCM_ENC_WR_PTR[29:0] */ | ||
598 | #define TW5864_ADPCM_ENC_WR_PTR1 0x401c | ||
599 | /* ADPCM_ENC_WR_PTR[50:30] */ | ||
600 | #define TW5864_ADPCM_ENC_WR_PTR2 0x4020 | ||
601 | |||
602 | /* ADPCM_ENC_RD_PTR[29:0] */ | ||
603 | #define TW5864_ADPCM_ENC_RD_PTR1 0x4024 | ||
604 | /* ADPCM_ENC_RD_PTR[50:30] */ | ||
605 | #define TW5864_ADPCM_ENC_RD_PTR2 0x4028 | ||
606 | |||
607 | /* [3:0] rd ch0, [7:4] rd ch1, [11:8] wr ch0, [15:12] wr ch1 */ | ||
608 | #define TW5864_ADPCM_DEC_RD_WR_PTR 0x402c | ||
609 | |||
610 | /* | ||
611 | * For TW5864_AD_ORIG_WR_PTR, TW5864_AD_ORIG_RD_PTR: | ||
612 | * Bit[3:0] ch0 | ||
613 | * Bit[7:4] ch1 | ||
614 | * Bit[11:8] ch2 | ||
615 | * Bit[15:12] ch3 | ||
616 | * Bit[19:16] ch4 | ||
617 | * Bit[23:20] ch5 | ||
618 | * Bit[27:24] ch6 | ||
619 | * Bit[31:28] ch7 | ||
620 | * Bit[35:32] ch8 | ||
621 | * Bit[39:36] ch9 | ||
622 | * Bit[43:40] ch10 | ||
623 | * Bit[47:44] ch11 | ||
624 | * Bit[51:48] ch12 | ||
625 | * Bit[55:52] ch13 | ||
626 | * Bit[59:56] ch14 | ||
627 | * Bit[63:60] ch15 | ||
628 | * Bit[67:64] ch16 | ||
629 | */ | ||
630 | /* AD_ORIG_WR_PTR[31:0] */ | ||
631 | #define TW5864_AD_ORIG_WR_PTR1 0x4030 | ||
632 | /* AD_ORIG_WR_PTR[63:32] */ | ||
633 | #define TW5864_AD_ORIG_WR_PTR2 0x4034 | ||
634 | /* AD_ORIG_WR_PTR[67:64] */ | ||
635 | #define TW5864_AD_ORIG_WR_PTR3 0x4038 | ||
636 | |||
637 | /* AD_ORIG_RD_PTR[31:0] */ | ||
638 | #define TW5864_AD_ORIG_RD_PTR1 0x403c | ||
639 | /* AD_ORIG_RD_PTR[63:32] */ | ||
640 | #define TW5864_AD_ORIG_RD_PTR2 0x4040 | ||
641 | /* AD_ORIG_RD_PTR[67:64] */ | ||
642 | #define TW5864_AD_ORIG_RD_PTR3 0x4044 | ||
643 | |||
644 | #define TW5864_PC_BLOCK_ORIG_RD_NO 0x4048 | ||
645 | #define TW5864_PC_BLOCK_ORIG_RD_NO_MASK 0x1f | ||
646 | |||
647 | #define TW5864_PCI_AUD 0x404c | ||
648 | /* Define controls in register TW5864_PCI_AUD */ | ||
649 | /* | ||
650 | * The register is applicable to PCI initiator mode only. Used to select PCM(0) | ||
651 | * or ADPCM(1) audio data sent to PC. One bit for each channel | ||
652 | */ | ||
653 | #define TW5864_PCI_DATA_SEL 0xffff | ||
654 | /* | ||
655 | * Audio flow control mode selection bit. | ||
656 | * 0 Flow control disabled. TW5864 continuously sends audio frame to PC | ||
657 | * (initiator mode) | ||
658 | * 1 Flow control enabled | ||
659 | */ | ||
660 | #define TW5864_PCI_FLOW_EN BIT(16) | ||
661 | /* | ||
662 | * When PCI_FLOW_EN is set, PCI need to toggle this bit to send an audio frame | ||
663 | * to PC. One toggle to send one frame. | ||
664 | */ | ||
665 | #define TW5864_PCI_AUD_FRM_EN BIT(17) | ||
666 | |||
667 | /* [1:0] CS valid to data valid CLK cycles when writing operation */ | ||
668 | #define TW5864_CS2DAT_CNT 0x8000 | ||
669 | /* [2:0] Data valid signal width by system clock cycles */ | ||
670 | #define TW5864_DATA_VLD_WIDTH 0x8004 | ||
671 | |||
672 | #define TW5864_SYNC 0x8008 | ||
673 | /* Define controls in register TW5864_SYNC */ | ||
674 | /* | ||
675 | * 0 vlc stream to syncrous port | ||
676 | * 1 vlc stream to ddr buffers | ||
677 | */ | ||
678 | #define TW5864_SYNC_CFG BIT(7) | ||
679 | /* | ||
680 | * 0 SYNC Address sampled on Rising edge | ||
681 | * 1 SYNC Address sampled on Falling edge | ||
682 | */ | ||
683 | #define TW5864_SYNC_ADR_EDGE BIT(0) | ||
684 | #define TW5864_VLC_STR_DELAY_SHIFT 1 | ||
685 | /* | ||
686 | * 0 No system delay | ||
687 | * 1 One system clock delay | ||
688 | * 2 Two system clock delay | ||
689 | * 3 Three system clock delay | ||
690 | */ | ||
691 | #define TW5864_VLC_STR_DELAY (3 << 1) | ||
692 | /* | ||
693 | * 0 Rising edge output | ||
694 | * 1 Falling edge output | ||
695 | */ | ||
696 | #define TW5864_VLC_OUT_EDGE BIT(3) | ||
697 | |||
698 | /* | ||
699 | * [1:0] | ||
700 | * 2’b00 phase set to 180 degree | ||
701 | * 2’b01 phase set to 270 degree | ||
702 | * 2’b10 phase set to 0 degree | ||
703 | * 2’b11 phase set to 90 degree | ||
704 | */ | ||
705 | #define TW5864_I2C_PHASE_CFG 0x800c | ||
706 | |||
707 | /* | ||
708 | * The system / DDR clock (166 MHz) is generated with an on-chip system clock | ||
709 | * PLL (SYSPLL) using input crystal clock of 27 MHz. The system clock PLL | ||
710 | * frequency is controlled with the following equation. | ||
711 | * CLK_OUT = CLK_IN * (M+1) / ((N+1) * P) | ||
712 | * SYSPLL_M M parameter | ||
713 | * SYSPLL_N N parameter | ||
714 | * SYSPLL_P P parameter | ||
715 | */ | ||
716 | /* SYSPLL_M[7:0] */ | ||
717 | #define TW5864_SYSPLL1 0x8018 | ||
718 | /* Define controls in register TW5864_SYSPLL1 */ | ||
719 | #define TW5864_SYSPLL_M_LOW 0x00ff | ||
720 | |||
721 | /* [2:0]: SYSPLL_M[10:8], [7:3]: SYSPLL_N[4:0] */ | ||
722 | #define TW5864_SYSPLL2 0x8019 | ||
723 | /* Define controls in register TW5864_SYSPLL2 */ | ||
724 | #define TW5864_SYSPLL_M_HI 0x07 | ||
725 | #define TW5864_SYSPLL_N_LOW_SHIFT 3 | ||
726 | #define TW5864_SYSPLL_N_LOW (0x1f << 3) | ||
727 | |||
728 | /* | ||
729 | * [1:0]: SYSPLL_N[6:5], [3:2]: SYSPLL_P, [4]: SYSPLL_IREF, [7:5]: SYSPLL_CP_SEL | ||
730 | */ | ||
731 | #define TW5864_SYSPLL3 0x8020 | ||
732 | /* Define controls in register TW5864_SYSPLL3 */ | ||
733 | #define TW5864_SYSPLL_N_HI 0x03 | ||
734 | #define TW5864_SYSPLL_P_SHIFT 2 | ||
735 | #define TW5864_SYSPLL_P (0x03 << 2) | ||
736 | /* | ||
737 | * SYSPLL bias current control | ||
738 | * 0 Lower current (default) | ||
739 | * 1 30% higher current | ||
740 | */ | ||
741 | #define TW5864_SYSPLL_IREF BIT(4) | ||
742 | /* | ||
743 | * SYSPLL charge pump current selection | ||
744 | * 0 1,5 uA | ||
745 | * 1 4 uA | ||
746 | * 2 9 uA | ||
747 | * 3 19 uA | ||
748 | * 4 39 uA | ||
749 | * 5 79 uA | ||
750 | * 6 159 uA | ||
751 | * 7 319 uA | ||
752 | */ | ||
753 | #define TW5864_SYSPLL_CP_SEL_SHIFT 5 | ||
754 | #define TW5864_SYSPLL_CP_SEL (0x07 << 5) | ||
755 | |||
756 | /* | ||
757 | * [1:0]: SYSPLL_VCO, [3:2]: SYSPLL_LP_X8, [5:4]: SYSPLL_ICP_SEL, | ||
758 | * [6]: SYSPLL_LPF_5PF, [7]: SYSPLL_ED_SEL | ||
759 | */ | ||
760 | #define TW5864_SYSPLL4 0x8021 | ||
761 | /* Define controls in register TW5864_SYSPLL4 */ | ||
762 | /* | ||
763 | * SYSPLL_VCO VCO Range selection | ||
764 | * 00 5 ~ 75 MHz | ||
765 | * 01 50 ~ 140 MHz | ||
766 | * 10 110 ~ 320 MHz | ||
767 | * 11 270 ~ 700 MHz | ||
768 | */ | ||
769 | #define TW5864_SYSPLL_VCO 0x03 | ||
770 | #define TW5864_SYSPLL_LP_X8_SHIFT 2 | ||
771 | /* | ||
772 | * Loop resister | ||
773 | * 0 38.5K ohms | ||
774 | * 1 6.6K ohms (default) | ||
775 | * 2 2.2K ohms | ||
776 | * 3 1.1K ohms | ||
777 | */ | ||
778 | #define TW5864_SYSPLL_LP_X8 (0x03 << 2) | ||
779 | #define TW5864_SYSPLL_ICP_SEL_SHIFT 4 | ||
780 | /* | ||
781 | * PLL charge pump fine tune | ||
782 | * 00 x1 (default) | ||
783 | * 01 x1/2 | ||
784 | * 10 x1/7 | ||
785 | * 11 x1/8 | ||
786 | */ | ||
787 | #define TW5864_SYSPLL_ICP_SEL (0x03 << 4) | ||
788 | /* | ||
789 | * PLL low pass filter phase margin adjustment | ||
790 | * 0 no 5pF (default) | ||
791 | * 1 5pF added | ||
792 | */ | ||
793 | #define TW5864_SYSPLL_LPF_5PF BIT(6) | ||
794 | /* | ||
795 | * PFD select edge for detection | ||
796 | * 0 Falling edge (default) | ||
797 | * 1 Rising edge | ||
798 | */ | ||
799 | #define TW5864_SYSPLL_ED_SEL BIT(7) | ||
800 | |||
801 | /* [0]: SYSPLL_RST, [4]: SYSPLL_PD */ | ||
802 | #define TW5864_SYSPLL5 0x8024 | ||
803 | /* Define controls in register TW5864_SYSPLL5 */ | ||
804 | /* Reset SYSPLL */ | ||
805 | #define TW5864_SYSPLL_RST BIT(0) | ||
806 | /* Power down SYSPLL */ | ||
807 | #define TW5864_SYSPLL_PD BIT(4) | ||
808 | |||
809 | #define TW5864_PLL_CFG 0x801c | ||
810 | /* Define controls in register TW5864_PLL_CFG */ | ||
811 | /* | ||
812 | * Issue Soft Reset from Async Host Interface / PCI Interface clock domain. | ||
813 | * Become valid after sync to the xtal clock domain. This bit is set only if | ||
814 | * LOAD register bit is also set to 1. | ||
815 | */ | ||
816 | #define TW5864_SRST BIT(0) | ||
817 | /* | ||
818 | * Issue SYSPLL (166 MHz) configuration latch from Async host interface / PCI | ||
819 | * Interface clock domain. The configuration setting becomes effective only if | ||
820 | * LOAD register bit is also set to 1. | ||
821 | */ | ||
822 | #define TW5864_SYSPLL_CFG BIT(2) | ||
823 | /* | ||
824 | * Issue SPLL (108 MHz) configuration load from Async host interface / PCI | ||
825 | * Interface clock domain. The configuration setting becomes effective only if | ||
826 | * the LOAD register bit is also set to 1. | ||
827 | */ | ||
828 | #define TW5864_SPLL_CFG BIT(4) | ||
829 | /* | ||
830 | * Set this bit to latch the SRST, SYSPLL_CFG, SPLL_CFG setting into the xtal | ||
831 | * clock domain to restart the PLL. This bit is self cleared. | ||
832 | */ | ||
833 | #define TW5864_LOAD BIT(3) | ||
834 | |||
835 | /* SPLL_IREF, SPLL_LPX4, SPLL_CPX4, SPLL_PD, SPLL_DBG */ | ||
836 | #define TW5864_SPLL 0x8028 | ||
837 | |||
838 | /* 0x8800 ~ 0x88fc -- Interrupt Register Map */ | ||
839 | /* | ||
840 | * Trigger mode of interrupt source 0 ~ 15 | ||
841 | * 1 Edge trigger mode | ||
842 | * 0 Level trigger mode | ||
843 | */ | ||
844 | #define TW5864_TRIGGER_MODE_L 0x8800 | ||
845 | /* Trigger mode of interrupt source 16 ~ 31 */ | ||
846 | #define TW5864_TRIGGER_MODE_H 0x8804 | ||
847 | /* Enable of interrupt source 0 ~ 15 */ | ||
848 | #define TW5864_INTR_ENABLE_L 0x8808 | ||
849 | /* Enable of interrupt source 16 ~ 31 */ | ||
850 | #define TW5864_INTR_ENABLE_H 0x880c | ||
851 | /* Clear interrupt command of interrupt source 0 ~ 15 */ | ||
852 | #define TW5864_INTR_CLR_L 0x8810 | ||
853 | /* Clear interrupt command of interrupt source 16 ~ 31 */ | ||
854 | #define TW5864_INTR_CLR_H 0x8814 | ||
855 | /* | ||
856 | * Assertion of interrupt source 0 ~ 15 | ||
857 | * 1 High level or pos-edge is assertion | ||
858 | * 0 Low level or neg-edge is assertion | ||
859 | */ | ||
860 | #define TW5864_INTR_ASSERT_L 0x8818 | ||
861 | /* Assertion of interrupt source 16 ~ 31 */ | ||
862 | #define TW5864_INTR_ASSERT_H 0x881c | ||
863 | /* | ||
864 | * Output level of interrupt | ||
865 | * 1 Interrupt output is high assertion | ||
866 | * 0 Interrupt output is low assertion | ||
867 | */ | ||
868 | #define TW5864_INTR_OUT_LEVEL 0x8820 | ||
869 | /* | ||
870 | * Status of interrupt source 0 ~ 15 | ||
871 | * Bit[0]: VLC 4k RAM interrupt | ||
872 | * Bit[1]: BURST DDR RAM interrupt | ||
873 | * Bit[2]: MV DSP interrupt | ||
874 | * Bit[3]: video lost interrupt | ||
875 | * Bit[4]: gpio 0 interrupt | ||
876 | * Bit[5]: gpio 1 interrupt | ||
877 | * Bit[6]: gpio 2 interrupt | ||
878 | * Bit[7]: gpio 3 interrupt | ||
879 | * Bit[8]: gpio 4 interrupt | ||
880 | * Bit[9]: gpio 5 interrupt | ||
881 | * Bit[10]: gpio 6 interrupt | ||
882 | * Bit[11]: gpio 7 interrupt | ||
883 | * Bit[12]: JPEG interrupt | ||
884 | * Bit[13:15]: Reserved | ||
885 | */ | ||
886 | #define TW5864_INTR_STATUS_L 0x8838 | ||
887 | /* | ||
888 | * Status of interrupt source 16 ~ 31 | ||
889 | * Bit[0]: Reserved | ||
890 | * Bit[1]: VLC done interrupt | ||
891 | * Bit[2]: Reserved | ||
892 | * Bit[3]: AD Vsync interrupt | ||
893 | * Bit[4]: Preview eof interrupt | ||
894 | * Bit[5]: Preview overflow interrupt | ||
895 | * Bit[6]: Timer interrupt | ||
896 | * Bit[7]: Reserved | ||
897 | * Bit[8]: Audio eof interrupt | ||
898 | * Bit[9]: I2C done interrupt | ||
899 | * Bit[10]: AD interrupt | ||
900 | * Bit[11:15]: Reserved | ||
901 | */ | ||
902 | #define TW5864_INTR_STATUS_H 0x883c | ||
903 | |||
904 | /* Defines of interrupt bits, united for both low and high word registers */ | ||
905 | #define TW5864_INTR_VLC_RAM BIT(0) | ||
906 | #define TW5864_INTR_BURST BIT(1) | ||
907 | #define TW5864_INTR_MV_DSP BIT(2) | ||
908 | #define TW5864_INTR_VIN_LOST BIT(3) | ||
909 | /* n belongs to [0; 7] */ | ||
910 | #define TW5864_INTR_GPIO(n) (1 << (4 + n)) | ||
911 | #define TW5864_INTR_JPEG BIT(12) | ||
912 | #define TW5864_INTR_VLC_DONE BIT(17) | ||
913 | #define TW5864_INTR_AD_VSYNC BIT(19) | ||
914 | #define TW5864_INTR_PV_EOF BIT(20) | ||
915 | #define TW5864_INTR_PV_OVERFLOW BIT(21) | ||
916 | #define TW5864_INTR_TIMER BIT(22) | ||
917 | #define TW5864_INTR_AUD_EOF BIT(24) | ||
918 | #define TW5864_INTR_I2C_DONE BIT(25) | ||
919 | #define TW5864_INTR_AD BIT(26) | ||
920 | |||
921 | /* 0x9000 ~ 0x920c -- Video Capture (VIF) Register Map */ | ||
922 | /* | ||
923 | * H264EN_CH_STATUS[n] Status of Vsync synchronized H264EN_CH_EN (Read Only) | ||
924 | * 1 Channel Enabled | ||
925 | * 0 Channel Disabled | ||
926 | */ | ||
927 | #define TW5864_H264EN_CH_STATUS 0x9000 | ||
928 | /* | ||
929 | * [15:0] H264EN_CH_EN[n] H264 Encoding Path Enable for channel | ||
930 | * 1 Channel Enabled | ||
931 | * 0 Channel Disabled | ||
932 | */ | ||
933 | #define TW5864_H264EN_CH_EN 0x9004 | ||
934 | /* | ||
935 | * H264EN_CH_DNS[n] H264 Encoding Path Downscale Video Decoder Input for | ||
936 | * channel n | ||
937 | * 1 Downscale Y to 1/2 | ||
938 | * 0 Does not downscale | ||
939 | */ | ||
940 | #define TW5864_H264EN_CH_DNS 0x9008 | ||
941 | /* | ||
942 | * H264EN_CH_PROG[n] H264 Encoding Path channel n is progressive | ||
943 | * 1 Progressive (Not valid for TW5864) | ||
944 | * 0 Interlaced (TW5864 default) | ||
945 | */ | ||
946 | #define TW5864_H264EN_CH_PROG 0x900c | ||
947 | /* | ||
948 | * [3:0] H264EN_BUS_MAX_CH[n] | ||
949 | * H264 Encoding Path maximum number of channel on BUS n | ||
950 | * 0 Max 4 channels | ||
951 | * 1 Max 2 channels | ||
952 | */ | ||
953 | #define TW5864_H264EN_BUS_MAX_CH 0x9010 | ||
954 | |||
955 | /* | ||
956 | * H264EN_RATE_MAX_LINE_n H264 Encoding path Rate Mapping Maximum Line Number | ||
957 | * on Bus n | ||
958 | */ | ||
959 | #define TW5864_H264EN_RATE_MAX_LINE_EVEN 0x1f | ||
960 | #define TW5864_H264EN_RATE_MAX_LINE_ODD_SHIFT 5 | ||
961 | #define TW5864_H264EN_RATE_MAX_LINE_ODD (0x1f << 5) | ||
962 | /* | ||
963 | * [4:0] H264EN_RATE_MAX_LINE_0 | ||
964 | * [9:5] H264EN_RATE_MAX_LINE_1 | ||
965 | */ | ||
966 | #define TW5864_H264EN_RATE_MAX_LINE_REG1 0x9014 | ||
967 | /* | ||
968 | * [4:0] H264EN_RATE_MAX_LINE_2 | ||
969 | * [9:5] H264EN_RATE_MAX_LINE_3 | ||
970 | */ | ||
971 | #define TW5864_H264EN_RATE_MAX_LINE_REG2 0x9018 | ||
972 | |||
973 | /* | ||
974 | * H264EN_CHn_FMT H264 Encoding Path Format configuration of Channel n | ||
975 | * 00 D1 (For D1 and hD1 frame) | ||
976 | * 01 (Reserved) | ||
977 | * 10 (Reserved) | ||
978 | * 11 D1 with 1/2 size in X (for CIF frame) | ||
979 | * Note: To be used with 0x9008 register to configure the frame size | ||
980 | */ | ||
981 | /* | ||
982 | * [1:0]: H264EN_CH0_FMT, | ||
983 | * ..., [15:14]: H264EN_CH7_FMT | ||
984 | */ | ||
985 | #define TW5864_H264EN_CH_FMT_REG1 0x9020 | ||
986 | /* | ||
987 | * [1:0]: H264EN_CH8_FMT (?), | ||
988 | * ..., [15:14]: H264EN_CH15_FMT (?) | ||
989 | */ | ||
990 | #define TW5864_H264EN_CH_FMT_REG2 0x9024 | ||
991 | |||
992 | /* | ||
993 | * H264EN_RATE_CNTL_BUSm_CHn H264 Encoding Path BUS m Rate Control for Channel n | ||
994 | */ | ||
995 | #define TW5864_H264EN_RATE_CNTL_LO_WORD(bus, channel) \ | ||
996 | (0x9100 + bus * 0x20 + channel * 0x08) | ||
997 | #define TW5864_H264EN_RATE_CNTL_HI_WORD(bus, channel) \ | ||
998 | (0x9104 + bus * 0x20 + channel * 0x08) | ||
999 | |||
1000 | /* | ||
1001 | * H264EN_BUSm_MAP_CHn The 16-to-1 MUX configuration register for each encoding | ||
1002 | * channel (total of 16 channels). Four bits for each channel. | ||
1003 | */ | ||
1004 | #define TW5864_H264EN_BUS0_MAP 0x9200 | ||
1005 | #define TW5864_H264EN_BUS1_MAP 0x9204 | ||
1006 | #define TW5864_H264EN_BUS2_MAP 0x9208 | ||
1007 | #define TW5864_H264EN_BUS3_MAP 0x920c | ||
1008 | |||
1009 | /* This register is not defined in datasheet, but used in reference driver */ | ||
1010 | #define TW5864_UNDECLARED_ERROR_FLAGS_0x9218 0x9218 | ||
1011 | |||
1012 | #define TW5864_GPIO1 0x9800 | ||
1013 | #define TW5864_GPIO2 0x9804 | ||
1014 | /* Define controls in registers TW5864_GPIO1, TW5864_GPIO2 */ | ||
1015 | /* GPIO DATA of Group n */ | ||
1016 | #define TW5864_GPIO_DATA 0x00ff | ||
1017 | #define TW5864_GPIO_OEN_SHIFT 8 | ||
1018 | /* GPIO Output Enable of Group n */ | ||
1019 | #define TW5864_GPIO_OEN (0xff << 8) | ||
1020 | |||
1021 | /* 0xa000 ~ 0xa8ff – DDR Controller Register Map */ | ||
1022 | /* DDR Controller A */ | ||
1023 | /* | ||
1024 | * [2:0] Data valid counter after read command to DDR. This is the delay value | ||
1025 | * to show how many cycles the data will be back from DDR after we issue a read | ||
1026 | * command. | ||
1027 | */ | ||
1028 | #define TW5864_RD_ACK_VLD_MUX 0xa000 | ||
1029 | |||
1030 | #define TW5864_DDR_PERIODS 0xa004 | ||
1031 | /* Define controls in register TW5864_DDR_PERIODS */ | ||
1032 | /* | ||
1033 | * Tras value, the minimum cycle of active to precharge command period, | ||
1034 | * default is 7 | ||
1035 | */ | ||
1036 | #define TW5864_TRAS_CNT_MAX 0x000f | ||
1037 | /* | ||
1038 | * Trfc value, the minimum cycle of refresh to active or refresh command period, | ||
1039 | * default is 4"hf | ||
1040 | */ | ||
1041 | #define TW5864_RFC_CNT_MAX_SHIFT 8 | ||
1042 | #define TW5864_RFC_CNT_MAX (0x0f << 8) | ||
1043 | /* | ||
1044 | * Trcd value, the minimum cycle of active to internal read/write command | ||
1045 | * period, default is 4"h2 | ||
1046 | */ | ||
1047 | #define TW5864_TCD_CNT_MAX_SHIFT 4 | ||
1048 | #define TW5864_TCD_CNT_MAX (0x0f << 4) | ||
1049 | /* Twr value, write recovery time, default is 4"h3 */ | ||
1050 | #define TW5864_TWR_CNT_MAX_SHIFT 12 | ||
1051 | #define TW5864_TWR_CNT_MAX (0x0f << 12) | ||
1052 | |||
1053 | /* | ||
1054 | * [2:0] CAS latency, the delay cycle between internal read command and the | ||
1055 | * availability of the first bit of output data, default is 3 | ||
1056 | */ | ||
1057 | #define TW5864_CAS_LATENCY 0xa008 | ||
1058 | /* | ||
1059 | * [15:0] Maximum average periodic refresh, the value is based on the current | ||
1060 | * frequency to match 7.8mcs | ||
1061 | */ | ||
1062 | #define TW5864_DDR_REF_CNTR_MAX 0xa00c | ||
1063 | /* | ||
1064 | * DDR_ON_CHIP_MAP [1:0] | ||
1065 | * 0 256M DDR on board | ||
1066 | * 1 512M DDR on board | ||
1067 | * 2 1G DDR on board | ||
1068 | * DDR_ON_CHIP_MAP [2] | ||
1069 | * 0 Only one DDR chip | ||
1070 | * 1 Two DDR chips | ||
1071 | */ | ||
1072 | #define TW5864_DDR_ON_CHIP_MAP 0xa01c | ||
1073 | #define TW5864_DDR_SELFTEST_MODE 0xa020 | ||
1074 | /* Define controls in register TW5864_DDR_SELFTEST_MODE */ | ||
1075 | /* | ||
1076 | * 0 Common read/write mode | ||
1077 | * 1 DDR self-test mode | ||
1078 | */ | ||
1079 | #define TW5864_MASTER_MODE BIT(0) | ||
1080 | /* | ||
1081 | * 0 DDR self-test single read/write | ||
1082 | * 1 DDR self-test burst read/write | ||
1083 | */ | ||
1084 | #define TW5864_SINGLE_PROC BIT(1) | ||
1085 | /* | ||
1086 | * 0 DDR self-test write command | ||
1087 | * 1 DDR self-test read command | ||
1088 | */ | ||
1089 | #define TW5864_WRITE_FLAG BIT(2) | ||
1090 | #define TW5864_DATA_MODE_SHIFT 4 | ||
1091 | /* | ||
1092 | * 0 write 32'haaaa5555 to DDR | ||
1093 | * 1 write 32'hffffffff to DDR | ||
1094 | * 2 write 32'hha5a55a5a to DDR | ||
1095 | * 3 write increasing data to DDR | ||
1096 | */ | ||
1097 | #define TW5864_DATA_MODE (0x3 << 4) | ||
1098 | |||
1099 | /* [7:0] The maximum data of one burst in DDR self-test mode */ | ||
1100 | #define TW5864_BURST_CNTR_MAX 0xa024 | ||
1101 | /* [15:0] The maximum burst counter (bit 15~0) in DDR self-test mode */ | ||
1102 | #define TW5864_DDR_PROC_CNTR_MAX_L 0xa028 | ||
1103 | /* The maximum burst counter (bit 31~16) in DDR self-test mode */ | ||
1104 | #define TW5864_DDR_PROC_CNTR_MAX_H 0xa02c | ||
1105 | /* [0]: Start one DDR self-test */ | ||
1106 | #define TW5864_DDR_SELF_TEST_CMD 0xa030 | ||
1107 | /* The maximum error counter (bit 15 ~ 0) in DDR self-test */ | ||
1108 | #define TW5864_ERR_CNTR_L 0xa034 | ||
1109 | |||
1110 | #define TW5864_ERR_CNTR_H_AND_FLAG 0xa038 | ||
1111 | /* Define controls in register TW5864_ERR_CNTR_H_AND_FLAG */ | ||
1112 | /* The maximum error counter (bit 30 ~ 16) in DDR self-test */ | ||
1113 | #define TW5864_ERR_CNTR_H_MASK 0x3fff | ||
1114 | /* DDR self-test end flag */ | ||
1115 | #define TW5864_END_FLAG 0x8000 | ||
1116 | |||
1117 | /* | ||
1118 | * DDR Controller B: same as 0xa000 ~ 0xa038, but add TW5864_DDR_B_OFFSET to all | ||
1119 | * addresses | ||
1120 | */ | ||
1121 | #define TW5864_DDR_B_OFFSET 0x0800 | ||
1122 | |||
1123 | /* 0xb004 ~ 0xb018 – HW version/ARB12 Register Map */ | ||
1124 | /* [15:0] Default is C013 */ | ||
1125 | #define TW5864_HW_VERSION 0xb004 | ||
1126 | |||
1127 | #define TW5864_REQS_ENABLE 0xb010 | ||
1128 | /* Define controls in register TW5864_REQS_ENABLE */ | ||
1129 | /* Audio data in to DDR enable (default 1) */ | ||
1130 | #define TW5864_AUD_DATA_IN_ENB BIT(0) | ||
1131 | /* Audio encode request to DDR enable (default 1) */ | ||
1132 | #define TW5864_AUD_ENC_REQ_ENB BIT(1) | ||
1133 | /* Audio decode request0 to DDR enable (default 1) */ | ||
1134 | #define TW5864_AUD_DEC_REQ0_ENB BIT(2) | ||
1135 | /* Audio decode request1 to DDR enable (default 1) */ | ||
1136 | #define TW5864_AUD_DEC_REQ1_ENB BIT(3) | ||
1137 | /* VLC stream request to DDR enable (default 1) */ | ||
1138 | #define TW5864_VLC_STRM_REQ_ENB BIT(4) | ||
1139 | /* H264 MV request to DDR enable (default 1) */ | ||
1140 | #define TW5864_DVM_MV_REQ_ENB BIT(5) | ||
1141 | /* mux_core MVD request to DDR enable (default 1) */ | ||
1142 | #define TW5864_MVD_REQ_ENB BIT(6) | ||
1143 | /* mux_core MVD temp data request to DDR enable (default 1) */ | ||
1144 | #define TW5864_MVD_TMP_REQ_ENB BIT(7) | ||
1145 | /* JPEG request to DDR enable (default 1) */ | ||
1146 | #define TW5864_JPEG_REQ_ENB BIT(8) | ||
1147 | /* mv_flag request to DDR enable (default 1) */ | ||
1148 | #define TW5864_MV_FLAG_REQ_ENB BIT(9) | ||
1149 | |||
1150 | #define TW5864_ARB12 0xb018 | ||
1151 | /* Define controls in register TW5864_ARB12 */ | ||
1152 | /* ARB12 Enable (default 1) */ | ||
1153 | #define TW5864_ARB12_ENB BIT(15) | ||
1154 | /* ARB12 maximum value of time out counter (default 15"h1FF) */ | ||
1155 | #define TW5864_ARB12_TIME_OUT_CNT 0x7fff | ||
1156 | |||
1157 | /* 0xb800 ~ 0xb80c -- Indirect Access Register Map */ | ||
1158 | /* | ||
1159 | * Spec says: | ||
1160 | * In order to access the indirect register space, the following procedure is | ||
1161 | * followed. | ||
1162 | * But reference driver implementation, and current driver, too, does it | ||
1163 | * differently. | ||
1164 | * | ||
1165 | * Write Registers: | ||
1166 | * (1) Write IND_DATA at 0xb804 ~ 0xb807 | ||
1167 | * (2) Read BUSY flag from 0xb803. Wait until BUSY signal is 0. | ||
1168 | * (3) Write IND_ADDR at 0xb800 ~ 0xb801. Set R/W to "1", ENABLE to "1" | ||
1169 | * Read Registers: | ||
1170 | * (1) Read BUSY flag from 0xb803. Wait until BUSY signal is 0. | ||
1171 | * (2) Write IND_ADDR at 0xb800 ~ 0xb801. Set R/W to "0", ENABLE to "1" | ||
1172 | * (3) Read BUSY flag from 0xb803. Wait until BUSY signal is 0. | ||
1173 | * (4) Read IND_DATA from 0xb804 ~ 0xb807 | ||
1174 | */ | ||
1175 | #define TW5864_IND_CTL 0xb800 | ||
1176 | /* Define controls in register TW5864_IND_CTL */ | ||
1177 | /* Address used to access indirect register space */ | ||
1178 | #define TW5864_IND_ADDR 0x0000ffff | ||
1179 | /* Wait until this bit is "0" before using indirect access */ | ||
1180 | #define TW5864_BUSY BIT(31) | ||
1181 | /* Activate the indirect access. This bit is self cleared */ | ||
1182 | #define TW5864_ENABLE BIT(25) | ||
1183 | /* Read/Write command */ | ||
1184 | #define TW5864_RW BIT(24) | ||
1185 | |||
1186 | /* [31:0] Data used to read/write indirect register space */ | ||
1187 | #define TW5864_IND_DATA 0xb804 | ||
1188 | |||
1189 | /* 0xc000 ~ 0xc7fc -- Preview Register Map */ | ||
1190 | /* Mostly skipped this section. */ | ||
1191 | /* | ||
1192 | * [15:0] Status of Vsync Synchronized PCI_PV_CH_EN (Read Only) | ||
1193 | * 1 Channel Enabled | ||
1194 | * 0 Channel Disabled | ||
1195 | */ | ||
1196 | #define TW5864_PCI_PV_CH_STATUS 0xc000 | ||
1197 | /* | ||
1198 | * [15:0] PCI Preview Path Enable for channel n | ||
1199 | * 1 Channel Enable | ||
1200 | * 0 Channel Disable | ||
1201 | */ | ||
1202 | #define TW5864_PCI_PV_CH_EN 0xc004 | ||
1203 | |||
1204 | /* 0xc800 ~ 0xc804 -- JPEG Capture Register Map */ | ||
1205 | /* Skipped. */ | ||
1206 | /* 0xd000 ~ 0xd0fc -- JPEG Control Register Map */ | ||
1207 | /* Skipped. */ | ||
1208 | |||
1209 | /* 0xe000 ~ 0xfc04 – Motion Vector Register Map */ | ||
1210 | |||
1211 | /* ME Motion Vector data (Four Byte Each) 0xe000 ~ 0xe7fc */ | ||
1212 | #define TW5864_ME_MV_VEC_START 0xe000 | ||
1213 | #define TW5864_ME_MV_VEC_MAX_OFFSET 0x1ff | ||
1214 | #define TW5864_ME_MV_VEC(offset) (TW5864_ME_MV_VEC_START + 4 * offset) | ||
1215 | |||
1216 | #define TW5864_MV 0xfc00 | ||
1217 | /* Define controls in register TW5864_MV */ | ||
1218 | /* mv bank0 full status , write "1" to clear */ | ||
1219 | #define TW5864_MV_BK0_FULL BIT(0) | ||
1220 | /* mv bank1 full status , write "1" to clear */ | ||
1221 | #define TW5864_MV_BK1_FULL BIT(1) | ||
1222 | /* slice end status; write "1" to clear */ | ||
1223 | #define TW5864_MV_EOF BIT(2) | ||
1224 | /* mv encode interrupt status; write "1" to clear */ | ||
1225 | #define TW5864_MV_DSP_INTR BIT(3) | ||
1226 | /* mv write memory overflow, write "1" to clear */ | ||
1227 | #define TW5864_DSP_WR_OF BIT(4) | ||
1228 | #define TW5864_MV_LEN_SHIFT 5 | ||
1229 | /* mv stream length */ | ||
1230 | #define TW5864_MV_LEN (0xff << 5) | ||
1231 | /* The configured status bit written into bit 15 of 0xfc04 */ | ||
1232 | #define TW5864_MPI_DDR_SEL BIT(13) | ||
1233 | |||
1234 | #define TW5864_MPI_DDR_SEL_REG 0xfc04 | ||
1235 | /* Define controls in register TW5864_MPI_DDR_SEL_REG */ | ||
1236 | /* | ||
1237 | * SW configure register | ||
1238 | * 0 MV is saved in internal DPR | ||
1239 | * 1 MV is saved in DDR | ||
1240 | */ | ||
1241 | #define TW5864_MPI_DDR_SEL2 BIT(15) | ||
1242 | |||
1243 | /* 0x18000 ~ 0x181fc – PCI Master/Slave Control Map */ | ||
1244 | #define TW5864_PCI_INTR_STATUS 0x18000 | ||
1245 | /* Define controls in register TW5864_PCI_INTR_STATUS */ | ||
1246 | /* vlc done */ | ||
1247 | #define TW5864_VLC_DONE_INTR BIT(1) | ||
1248 | /* ad vsync */ | ||
1249 | #define TW5864_AD_VSYNC_INTR BIT(3) | ||
1250 | /* preview eof */ | ||
1251 | #define TW5864_PREV_EOF_INTR BIT(4) | ||
1252 | /* preview overflow interrupt */ | ||
1253 | #define TW5864_PREV_OVERFLOW_INTR BIT(5) | ||
1254 | /* timer interrupt */ | ||
1255 | #define TW5864_TIMER_INTR BIT(6) | ||
1256 | /* audio eof */ | ||
1257 | #define TW5864_AUDIO_EOF_INTR BIT(8) | ||
1258 | /* IIC done */ | ||
1259 | #define TW5864_IIC_DONE_INTR BIT(24) | ||
1260 | /* ad interrupt (e.g.: video lost, video format changed) */ | ||
1261 | #define TW5864_AD_INTR_REG BIT(25) | ||
1262 | |||
1263 | #define TW5864_PCI_INTR_CTL 0x18004 | ||
1264 | /* Define controls in register TW5864_PCI_INTR_CTL */ | ||
1265 | /* master enable */ | ||
1266 | #define TW5864_PCI_MAST_ENB BIT(0) | ||
1267 | /* mvd&vlc master enable */ | ||
1268 | #define TW5864_MVD_VLC_MAST_ENB 0x06 | ||
1269 | /* (Need to set 0 in TW5864A) */ | ||
1270 | #define TW5864_AD_MAST_ENB BIT(3) | ||
1271 | /* preview master enable */ | ||
1272 | #define TW5864_PREV_MAST_ENB BIT(4) | ||
1273 | /* preview overflow enable */ | ||
1274 | #define TW5864_PREV_OVERFLOW_ENB BIT(5) | ||
1275 | /* timer interrupt enable */ | ||
1276 | #define TW5864_TIMER_INTR_ENB BIT(6) | ||
1277 | /* JPEG master (push mode) enable */ | ||
1278 | #define TW5864_JPEG_MAST_ENB BIT(7) | ||
1279 | #define TW5864_AU_MAST_ENB_CHN_SHIFT 8 | ||
1280 | /* audio master channel enable */ | ||
1281 | #define TW5864_AU_MAST_ENB_CHN (0xffff << 8) | ||
1282 | /* IIC interrupt enable */ | ||
1283 | #define TW5864_IIC_INTR_ENB BIT(24) | ||
1284 | /* ad interrupt enable */ | ||
1285 | #define TW5864_AD_INTR_ENB BIT(25) | ||
1286 | /* target burst enable */ | ||
1287 | #define TW5864_PCI_TAR_BURST_ENB BIT(26) | ||
1288 | /* vlc stream burst enable */ | ||
1289 | #define TW5864_PCI_VLC_BURST_ENB BIT(27) | ||
1290 | /* ddr burst enable (1 enable, and must set DDR_BRST_EN) */ | ||
1291 | #define TW5864_PCI_DDR_BURST_ENB BIT(28) | ||
1292 | |||
1293 | /* | ||
1294 | * Because preview and audio have 16 channels separately, so using this | ||
1295 | * registers to indicate interrupt status for every channels. This is secondary | ||
1296 | * interrupt status register. OR operating of the PREV_INTR_REG is | ||
1297 | * PREV_EOF_INTR, OR operating of the AU_INTR_REG bits is AUDIO_EOF_INTR | ||
1298 | */ | ||
1299 | #define TW5864_PREV_AND_AU_INTR 0x18008 | ||
1300 | /* Define controls in register TW5864_PREV_AND_AU_INTR */ | ||
1301 | /* preview eof interrupt flag */ | ||
1302 | #define TW5864_PREV_INTR_REG 0x0000ffff | ||
1303 | #define TW5864_AU_INTR_REG_SHIFT 16 | ||
1304 | /* audio eof interrupt flag */ | ||
1305 | #define TW5864_AU_INTR_REG (0xffff << 16) | ||
1306 | |||
1307 | #define TW5864_MASTER_ENB_REG 0x1800c | ||
1308 | /* Define controls in register TW5864_MASTER_ENB_REG */ | ||
1309 | /* master enable */ | ||
1310 | #define TW5864_PCI_VLC_INTR_ENB BIT(1) | ||
1311 | /* mvd and vlc master enable */ | ||
1312 | #define TW5864_PCI_PREV_INTR_ENB BIT(4) | ||
1313 | /* ad vsync master enable */ | ||
1314 | #define TW5864_PCI_PREV_OF_INTR_ENB BIT(5) | ||
1315 | /* jpeg master enable */ | ||
1316 | #define TW5864_PCI_JPEG_INTR_ENB BIT(7) | ||
1317 | /* preview master enable */ | ||
1318 | #define TW5864_PCI_AUD_INTR_ENB BIT(8) | ||
1319 | |||
1320 | /* | ||
1321 | * Every channel of preview and audio have ping-pong buffers in system memory, | ||
1322 | * this register is the buffer flag to notify software which buffer is been | ||
1323 | * operated. | ||
1324 | */ | ||
1325 | #define TW5864_PREV_AND_AU_BUF_FLAG 0x18010 | ||
1326 | /* Define controls in register TW5864_PREV_AND_AU_BUF_FLAG */ | ||
1327 | /* preview buffer A/B flag */ | ||
1328 | #define TW5864_PREV_BUF_FLAG 0xffff | ||
1329 | #define TW5864_AUDIO_BUF_FLAG_SHIFT 16 | ||
1330 | /* audio buffer A/B flag */ | ||
1331 | #define TW5864_AUDIO_BUF_FLAG (0xffff << 16) | ||
1332 | |||
1333 | #define TW5864_IIC 0x18014 | ||
1334 | /* Define controls in register TW5864_IIC */ | ||
1335 | /* register data */ | ||
1336 | #define TW5864_IIC_DATA 0x00ff | ||
1337 | #define TW5864_IIC_REG_ADDR_SHIFT 8 | ||
1338 | /* register addr */ | ||
1339 | #define TW5864_IIC_REG_ADDR (0xff << 8) | ||
1340 | /* rd/wr flag rd=1,wr=0 */ | ||
1341 | #define TW5864_IIC_RW BIT(16) | ||
1342 | #define TW5864_IIC_DEV_ADDR_SHIFT 17 | ||
1343 | /* device addr */ | ||
1344 | #define TW5864_IIC_DEV_ADDR (0x7f << 17) | ||
1345 | /* | ||
1346 | * iic done, software kick off one time iic transaction through setting this | ||
1347 | * bit to 1. Then poll this bit, value 1 indicate iic transaction have | ||
1348 | * completed, if read, valid data have been stored in iic_data | ||
1349 | */ | ||
1350 | #define TW5864_IIC_DONE BIT(24) | ||
1351 | |||
1352 | #define TW5864_RST_AND_IF_INFO 0x18018 | ||
1353 | /* Define controls in register TW5864_RST_AND_IF_INFO */ | ||
1354 | /* application software soft reset */ | ||
1355 | #define TW5864_APP_SOFT_RST BIT(0) | ||
1356 | #define TW5864_PCI_INF_VERSION_SHIFT 16 | ||
1357 | /* PCI interface version, read only */ | ||
1358 | #define TW5864_PCI_INF_VERSION (0xffff << 16) | ||
1359 | |||
1360 | /* vlc stream crc value, it is calculated in pci module */ | ||
1361 | #define TW5864_VLC_CRC_REG 0x1801c | ||
1362 | /* | ||
1363 | * vlc max length, it is defined by software based on software assign memory | ||
1364 | * space for vlc | ||
1365 | */ | ||
1366 | #define TW5864_VLC_MAX_LENGTH 0x18020 | ||
1367 | /* vlc length of one frame */ | ||
1368 | #define TW5864_VLC_LENGTH 0x18024 | ||
1369 | /* vlc original crc value */ | ||
1370 | #define TW5864_VLC_INTRA_CRC_I_REG 0x18028 | ||
1371 | /* vlc original crc value */ | ||
1372 | #define TW5864_VLC_INTRA_CRC_O_REG 0x1802c | ||
1373 | /* mv stream crc value, it is calculated in pci module */ | ||
1374 | #define TW5864_VLC_PAR_CRC_REG 0x18030 | ||
1375 | /* mv length */ | ||
1376 | #define TW5864_VLC_PAR_LENGTH_REG 0x18034 | ||
1377 | /* mv original crc value */ | ||
1378 | #define TW5864_VLC_PAR_I_REG 0x18038 | ||
1379 | /* mv original crc value */ | ||
1380 | #define TW5864_VLC_PAR_O_REG 0x1803c | ||
1381 | |||
1382 | /* | ||
1383 | * Configuration register for 9[or 10] CIFs or 1D1+15QCIF Preview mode. | ||
1384 | * PREV_PCI_ENB_CHN[0] Enable 9th preview channel (9CIF prev) or 1D1 channel in | ||
1385 | * (1D1+15QCIF prev) | ||
1386 | * PREV_PCI_ENB_CHN[1] Enable 10th preview channel | ||
1387 | */ | ||
1388 | #define TW5864_PREV_PCI_ENB_CHN 0x18040 | ||
1389 | /* Description skipped. */ | ||
1390 | #define TW5864_PREV_FRAME_FORMAT_IN 0x18044 | ||
1391 | /* IIC enable */ | ||
1392 | #define TW5864_IIC_ENB 0x18048 | ||
1393 | /* | ||
1394 | * Timer interrupt interval | ||
1395 | * 0 1ms | ||
1396 | * 1 2ms | ||
1397 | * 2 4ms | ||
1398 | * 3 8ms | ||
1399 | */ | ||
1400 | #define TW5864_PCI_INTTM_SCALE 0x1804c | ||
1401 | |||
1402 | /* | ||
1403 | * The above register is pci base address registers. Application software will | ||
1404 | * initialize them to tell chip where the corresponding stream will be dumped | ||
1405 | * to. Application software will select appropriate base address interval based | ||
1406 | * on the stream length. | ||
1407 | */ | ||
1408 | /* VLC stream base address */ | ||
1409 | #define TW5864_VLC_STREAM_BASE_ADDR 0x18080 | ||
1410 | /* MV stream base address */ | ||
1411 | #define TW5864_MV_STREAM_BASE_ADDR 0x18084 | ||
1412 | /* 0x180a0 – 0x180bc: audio burst base address. Skipped. */ | ||
1413 | /* 0x180c0 ~ 0x180dc – JPEG Push Mode Buffer Base Address. Skipped. */ | ||
1414 | /* 0x18100 – 0x1817c: preview burst base address. Skipped. */ | ||
1415 | |||
1416 | /* 0x80000 ~ 0x87fff -- DDR Burst RW Register Map */ | ||
1417 | #define TW5864_DDR_CTL 0x80000 | ||
1418 | /* Define controls in register TW5864_DDR_CTL */ | ||
1419 | #define TW5864_BRST_LENGTH_SHIFT 2 | ||
1420 | /* Length of 32-bit data burst */ | ||
1421 | #define TW5864_BRST_LENGTH (0x3fff << 2) | ||
1422 | /* | ||
1423 | * Burst Read/Write | ||
1424 | * 0 Read Burst from DDR | ||
1425 | * 1 Write Burst to DDR | ||
1426 | */ | ||
1427 | #define TW5864_BRST_RW BIT(16) | ||
1428 | /* Begin a new DDR Burst. This bit is self cleared */ | ||
1429 | #define TW5864_NEW_BRST_CMD BIT(17) | ||
1430 | /* DDR Burst End Flag */ | ||
1431 | #define TW5864_BRST_END BIT(24) | ||
1432 | /* Enable Error Interrupt for Single DDR Access */ | ||
1433 | #define TW5864_SING_ERR_INTR BIT(25) | ||
1434 | /* Enable Error Interrupt for Burst DDR Access */ | ||
1435 | #define TW5864_BRST_ERR_INTR BIT(26) | ||
1436 | /* Enable Interrupt for End of DDR Burst Access */ | ||
1437 | #define TW5864_BRST_END_INTR BIT(27) | ||
1438 | /* DDR Single Access Error Flag */ | ||
1439 | #define TW5864_SINGLE_ERR BIT(28) | ||
1440 | /* DDR Single Access Busy Flag */ | ||
1441 | #define TW5864_SINGLE_BUSY BIT(29) | ||
1442 | /* DDR Burst Access Error Flag */ | ||
1443 | #define TW5864_BRST_ERR BIT(30) | ||
1444 | /* DDR Burst Access Busy Flag */ | ||
1445 | #define TW5864_BRST_BUSY BIT(31) | ||
1446 | |||
1447 | /* [27:0] DDR Access Address. Bit [1:0] has to be 0 */ | ||
1448 | #define TW5864_DDR_ADDR 0x80004 | ||
1449 | /* DDR Access Internal Buffer Address. Bit [1:0] has to be 0 */ | ||
1450 | #define TW5864_DPR_BUF_ADDR 0x80008 | ||
1451 | /* SRAM Buffer MPI Access Space. Totally 16 KB */ | ||
1452 | #define TW5864_DPR_BUF_START 0x84000 | ||
1453 | /* 0x84000 - 0x87ffc */ | ||
1454 | #define TW5864_DPR_BUF_SIZE 0x4000 | ||
1455 | |||
1456 | /* Indirect Map Space */ | ||
1457 | /* | ||
1458 | * The indirect space is accessed through 0xb800 ~ 0xb807 registers in direct | ||
1459 | * access space | ||
1460 | */ | ||
1461 | /* Analog Video / Audio Decoder / Encoder */ | ||
1462 | /* Allowed channel values: [0; 3] */ | ||
1463 | /* Read-only register */ | ||
1464 | #define TW5864_INDIR_VIN_0(channel) (0x000 + channel * 0x010) | ||
1465 | /* Define controls in register TW5864_INDIR_VIN_0 */ | ||
1466 | /* | ||
1467 | * 1 Video not present. (sync is not detected in number of consecutive line | ||
1468 | * periods specified by MISSCNT register) | ||
1469 | * 0 Video detected. | ||
1470 | */ | ||
1471 | #define TW5864_INDIR_VIN_0_VDLOSS BIT(7) | ||
1472 | /* | ||
1473 | * 1 Horizontal sync PLL is locked to the incoming video source. | ||
1474 | * 0 Horizontal sync PLL is not locked. | ||
1475 | */ | ||
1476 | #define TW5864_INDIR_VIN_0_HLOCK BIT(6) | ||
1477 | /* | ||
1478 | * 1 Sub-carrier PLL is locked to the incoming video source. | ||
1479 | * 0 Sub-carrier PLL is not locked. | ||
1480 | */ | ||
1481 | #define TW5864_INDIR_VIN_0_SLOCK BIT(5) | ||
1482 | /* | ||
1483 | * 1 Even field is being decoded. | ||
1484 | * 0 Odd field is being decoded. | ||
1485 | */ | ||
1486 | #define TW5864_INDIR_VIN_0_FLD BIT(4) | ||
1487 | /* | ||
1488 | * 1 Vertical logic is locked to the incoming video source. | ||
1489 | * 0 Vertical logic is not locked. | ||
1490 | */ | ||
1491 | #define TW5864_INDIR_VIN_0_VLOCK BIT(3) | ||
1492 | /* | ||
1493 | * 1 No color burst signal detected. | ||
1494 | * 0 Color burst signal detected. | ||
1495 | */ | ||
1496 | #define TW5864_INDIR_VIN_0_MONO BIT(1) | ||
1497 | /* | ||
1498 | * 0 60Hz source detected | ||
1499 | * 1 50Hz source detected | ||
1500 | * The actual vertical scanning frequency depends on the current standard | ||
1501 | * invoked. | ||
1502 | */ | ||
1503 | #define TW5864_INDIR_VIN_0_DET50 BIT(0) | ||
1504 | |||
1505 | #define TW5864_INDIR_VIN_1(channel) (0x001 + channel * 0x010) | ||
1506 | /* VCR signal indicator. Read-only. */ | ||
1507 | #define TW5864_INDIR_VIN_1_VCR BIT(7) | ||
1508 | /* Weak signal indicator 2. Read-only. */ | ||
1509 | #define TW5864_INDIR_VIN_1_WKAIR BIT(6) | ||
1510 | /* Weak signal indicator controlled by WKTH. Read-only. */ | ||
1511 | #define TW5864_INDIR_VIN_1_WKAIR1 BIT(5) | ||
1512 | /* | ||
1513 | * 1 = Standard signal | ||
1514 | * 0 = Non-standard signal | ||
1515 | * Read-only | ||
1516 | */ | ||
1517 | #define TW5864_INDIR_VIN_1_VSTD BIT(4) | ||
1518 | /* | ||
1519 | * 1 = Non-interlaced signal | ||
1520 | * 0 = interlaced signal | ||
1521 | * Read-only | ||
1522 | */ | ||
1523 | #define TW5864_INDIR_VIN_1_NINTL BIT(3) | ||
1524 | /* | ||
1525 | * Vertical Sharpness Control. Writable. | ||
1526 | * 0 = None (default) | ||
1527 | * 7 = Highest | ||
1528 | * **Note: VSHP must be set to ‘0’ if COMB = 0 | ||
1529 | */ | ||
1530 | #define TW5864_INDIR_VIN_1_VSHP 0x07 | ||
1531 | |||
1532 | /* HDELAY_XY[7:0] */ | ||
1533 | #define TW5864_INDIR_VIN_2_HDELAY_XY_LO(channel) (0x002 + channel * 0x010) | ||
1534 | /* HACTIVE_XY[7:0] */ | ||
1535 | #define TW5864_INDIR_VIN_3_HACTIVE_XY_LO(channel) (0x003 + channel * 0x010) | ||
1536 | /* VDELAY_XY[7:0] */ | ||
1537 | #define TW5864_INDIR_VIN_4_VDELAY_XY_LO(channel) (0x004 + channel * 0x010) | ||
1538 | /* VACTIVE_XY[7:0] */ | ||
1539 | #define TW5864_INDIR_VIN_5_VACTIVE_XY_LO(channel) (0x005 + channel * 0x010) | ||
1540 | |||
1541 | #define TW5864_INDIR_VIN_6(channel) (0x006 + channel * 0x010) | ||
1542 | /* Define controls in register TW5864_INDIR_VIN_6 */ | ||
1543 | #define TW5864_INDIR_VIN_6_HDELAY_XY_HI 0x03 | ||
1544 | #define TW5864_INDIR_VIN_6_HACTIVE_XY_HI_SHIFT 2 | ||
1545 | #define TW5864_INDIR_VIN_6_HACTIVE_XY_HI (0x03 << 2) | ||
1546 | #define TW5864_INDIR_VIN_6_VDELAY_XY_HI BIT(4) | ||
1547 | #define TW5864_INDIR_VIN_6_VACTIVE_XY_HI BIT(5) | ||
1548 | |||
1549 | /* | ||
1550 | * HDELAY_XY This 10bit register defines the starting location of horizontal | ||
1551 | * active pixel for display / record path. A unit is 1 pixel. The default value | ||
1552 | * is 0x00f for NTSC and 0x00a for PAL. | ||
1553 | * | ||
1554 | * HACTIVE_XY This 10bit register defines the number of horizontal active pixel | ||
1555 | * for display / record path. A unit is 1 pixel. The default value is decimal | ||
1556 | * 720. | ||
1557 | * | ||
1558 | * VDELAY_XY This 9bit register defines the starting location of vertical | ||
1559 | * active for display / record path. A unit is 1 line. The default value is | ||
1560 | * decimal 6. | ||
1561 | * | ||
1562 | * VACTIVE_XY This 9bit register defines the number of vertical active lines | ||
1563 | * for display / record path. A unit is 1 line. The default value is decimal | ||
1564 | * 240. | ||
1565 | */ | ||
1566 | |||
1567 | /* HUE These bits control the color hue as 2's complement number. They have | ||
1568 | * value from +36o (7Fh) to -36o (80h) with an increment of 2.8o. The 2 LSB has | ||
1569 | * no effect. The positive value gives greenish tone and negative value gives | ||
1570 | * purplish tone. The default value is 0o (00h). This is effective only on NTSC | ||
1571 | * system. The default is 00h. | ||
1572 | */ | ||
1573 | #define TW5864_INDIR_VIN_7_HUE(channel) (0x007 + channel * 0x010) | ||
1574 | |||
1575 | #define TW5864_INDIR_VIN_8(channel) (0x008 + channel * 0x010) | ||
1576 | /* Define controls in register TW5864_INDIR_VIN_8 */ | ||
1577 | /* | ||
1578 | * This bit controls the center frequency of the peaking filter. | ||
1579 | * The corresponding gain adjustment is HFLT. | ||
1580 | * 0 Low | ||
1581 | * 1 center | ||
1582 | */ | ||
1583 | #define TW5864_INDIR_VIN_8_SCURVE BIT(7) | ||
1584 | /* CTI level selection. The default is 1. | ||
1585 | * 0 None | ||
1586 | * 3 Highest | ||
1587 | */ | ||
1588 | #define TW5864_INDIR_VIN_8_CTI_SHIFT 4 | ||
1589 | #define TW5864_INDIR_VIN_8_CTI (0x03 << 4) | ||
1590 | |||
1591 | /* | ||
1592 | * These bits control the amount of sharpness enhancement on the luminance | ||
1593 | * signals. There are 16 levels of control with "0" having no effect on the | ||
1594 | * output image. 1 through 15 provides sharpness enhancement with "F" being the | ||
1595 | * strongest. The default is 1. | ||
1596 | */ | ||
1597 | #define TW5864_INDIR_VIN_8_SHARPNESS 0x0f | ||
1598 | |||
1599 | /* | ||
1600 | * These bits control the luminance contrast gain. A value of 100 (64h) has a | ||
1601 | * gain of 1. The range adjustment is from 0% to 255% at 1% per step. The | ||
1602 | * default is 64h. | ||
1603 | */ | ||
1604 | #define TW5864_INDIR_VIN_9_CNTRST(channel) (0x009 + channel * 0x010) | ||
1605 | |||
1606 | /* | ||
1607 | * These bits control the brightness. They have value of –128 to 127 in 2's | ||
1608 | * complement form. Positive value increases brightness. A value 0 has no | ||
1609 | * effect on the data. The default is 00h. | ||
1610 | */ | ||
1611 | #define TW5864_INDIR_VIN_A_BRIGHT(channel) (0x00a + channel * 0x010) | ||
1612 | |||
1613 | /* | ||
1614 | * These bits control the digital gain adjustment to the U (or Cb) component of | ||
1615 | * the digital video signal. The color saturation can be adjusted by adjusting | ||
1616 | * the U and V color gain components by the same amount in the normal | ||
1617 | * situation. The U and V can also be adjusted independently to provide greater | ||
1618 | * flexibility. The range of adjustment is 0 to 200%. A value of 128 (80h) has | ||
1619 | * gain of 100%. The default is 80h. | ||
1620 | */ | ||
1621 | #define TW5864_INDIR_VIN_B_SAT_U(channel) (0x00b + channel * 0x010) | ||
1622 | |||
1623 | /* | ||
1624 | * These bits control the digital gain adjustment to the V (or Cr) component of | ||
1625 | * the digital video signal. The color saturation can be adjusted by adjusting | ||
1626 | * the U and V color gain components by the same amount in the normal | ||
1627 | * situation. The U and V can also be adjusted independently to provide greater | ||
1628 | * flexibility. The range of adjustment is 0 to 200%. A value of 128 (80h) has | ||
1629 | * gain of 100%. The default is 80h. | ||
1630 | */ | ||
1631 | #define TW5864_INDIR_VIN_C_SAT_V(channel) (0x00c + channel * 0x010) | ||
1632 | |||
1633 | /* Read-only */ | ||
1634 | #define TW5864_INDIR_VIN_D(channel) (0x00d + channel * 0x010) | ||
1635 | /* Define controls in register TW5864_INDIR_VIN_D */ | ||
1636 | /* Macrovision color stripe detection may be un-reliable */ | ||
1637 | #define TW5864_INDIR_VIN_D_CSBAD BIT(3) | ||
1638 | /* Macrovision AGC pulse detected */ | ||
1639 | #define TW5864_INDIR_VIN_D_MCVSN BIT(2) | ||
1640 | /* Macrovision color stripe protection burst detected */ | ||
1641 | #define TW5864_INDIR_VIN_D_CSTRIPE BIT(1) | ||
1642 | /* | ||
1643 | * This bit is valid only when color stripe protection is detected, i.e. if | ||
1644 | * CSTRIPE=1, | ||
1645 | * 1 Type 2 color stripe protection | ||
1646 | * 0 Type 3 color stripe protection | ||
1647 | */ | ||
1648 | #define TW5864_INDIR_VIN_D_CTYPE2 BIT(0) | ||
1649 | |||
1650 | /* Read-only */ | ||
1651 | #define TW5864_INDIR_VIN_E(channel) (0x00e + channel * 0x010) | ||
1652 | /* Define controls in register TW5864_INDIR_VIN_E */ | ||
1653 | /* | ||
1654 | * Read-only. | ||
1655 | * 0 Idle | ||
1656 | * 1 Detection in progress | ||
1657 | */ | ||
1658 | #define TW5864_INDIR_VIN_E_DETSTUS BIT(7) | ||
1659 | /* | ||
1660 | * STDNOW Current standard invoked | ||
1661 | * 0 NTSC (M) | ||
1662 | * 1 PAL (B, D, G, H, I) | ||
1663 | * 2 SECAM | ||
1664 | * 3 NTSC4.43 | ||
1665 | * 4 PAL (M) | ||
1666 | * 5 PAL (CN) | ||
1667 | * 6 PAL 60 | ||
1668 | * 7 Not valid | ||
1669 | */ | ||
1670 | #define TW5864_INDIR_VIN_E_STDNOW_SHIFT 4 | ||
1671 | #define TW5864_INDIR_VIN_E_STDNOW (0x07 << 4) | ||
1672 | |||
1673 | /* | ||
1674 | * 1 Disable the shadow registers | ||
1675 | * 0 Enable VACTIVE and HDELAY shadow registers value depending on STANDARD. | ||
1676 | * (Default) | ||
1677 | */ | ||
1678 | #define TW5864_INDIR_VIN_E_ATREG BIT(3) | ||
1679 | /* | ||
1680 | * STANDARD Standard selection | ||
1681 | * 0 NTSC (M) | ||
1682 | * 1 PAL (B, D, G, H, I) | ||
1683 | * 2 SECAM | ||
1684 | * 3 NTSC4.43 | ||
1685 | * 4 PAL (M) | ||
1686 | * 5 PAL (CN) | ||
1687 | * 6 PAL 60 | ||
1688 | * 7 Auto detection (Default) | ||
1689 | */ | ||
1690 | #define TW5864_INDIR_VIN_E_STANDARD 0x07 | ||
1691 | |||
1692 | #define TW5864_INDIR_VIN_F(channel) (0x00f + channel * 0x010) | ||
1693 | /* Define controls in register TW5864_INDIR_VIN_F */ | ||
1694 | /* | ||
1695 | * 1 Writing 1 to this bit will manually initiate the auto format detection | ||
1696 | * process. This bit is a self-clearing bit | ||
1697 | * 0 Manual initiation of auto format detection is done. (Default) | ||
1698 | */ | ||
1699 | #define TW5864_INDIR_VIN_F_ATSTART BIT(7) | ||
1700 | /* Enable recognition of PAL60 (Default) */ | ||
1701 | #define TW5864_INDIR_VIN_F_PAL60EN BIT(6) | ||
1702 | /* Enable recognition of PAL (CN). (Default) */ | ||
1703 | #define TW5864_INDIR_VIN_F_PALCNEN BIT(5) | ||
1704 | /* Enable recognition of PAL (M). (Default) */ | ||
1705 | #define TW5864_INDIR_VIN_F_PALMEN BIT(4) | ||
1706 | /* Enable recognition of NTSC 4.43. (Default) */ | ||
1707 | #define TW5864_INDIR_VIN_F_NTSC44EN BIT(3) | ||
1708 | /* Enable recognition of SECAM. (Default) */ | ||
1709 | #define TW5864_INDIR_VIN_F_SECAMEN BIT(2) | ||
1710 | /* Enable recognition of PAL (B, D, G, H, I). (Default) */ | ||
1711 | #define TW5864_INDIR_VIN_F_PALBEN BIT(1) | ||
1712 | /* Enable recognition of NTSC (M). (Default) */ | ||
1713 | #define TW5864_INDIR_VIN_F_NTSCEN BIT(0) | ||
1714 | |||
1715 | /* Some registers skipped. */ | ||
1716 | |||
1717 | /* Use falling edge to sample VD1-VD4 from 54 MHz to 108 MHz */ | ||
1718 | #define TW5864_INDIR_VD_108_POL 0x041 | ||
1719 | #define TW5864_INDIR_VD_108_POL_VD12 BIT(0) | ||
1720 | #define TW5864_INDIR_VD_108_POL_VD34 BIT(1) | ||
1721 | #define TW5864_INDIR_VD_108_POL_BOTH \ | ||
1722 | (TW5864_INDIR_VD_108_POL_VD12 | TW5864_INDIR_VD_108_POL_VD34) | ||
1723 | |||
1724 | /* Some registers skipped. */ | ||
1725 | |||
1726 | /* | ||
1727 | * Audio Input ADC gain control | ||
1728 | * 0 0.25 | ||
1729 | * 1 0.31 | ||
1730 | * 2 0.38 | ||
1731 | * 3 0.44 | ||
1732 | * 4 0.50 | ||
1733 | * 5 0.63 | ||
1734 | * 6 0.75 | ||
1735 | * 7 0.88 | ||
1736 | * 8 1.00 (default) | ||
1737 | * 9 1.25 | ||
1738 | * 10 1.50 | ||
1739 | * 11 1.75 | ||
1740 | * 12 2.00 | ||
1741 | * 13 2.25 | ||
1742 | * 14 2.50 | ||
1743 | * 15 2.75 | ||
1744 | */ | ||
1745 | /* [3:0] channel 0, [7:4] channel 1 */ | ||
1746 | #define TW5864_INDIR_AIGAIN1 0x060 | ||
1747 | /* [3:0] channel 2, [7:4] channel 3 */ | ||
1748 | #define TW5864_INDIR_AIGAIN2 0x061 | ||
1749 | |||
1750 | /* Some registers skipped */ | ||
1751 | |||
1752 | #define TW5864_INDIR_AIN_0x06D 0x06d | ||
1753 | /* Define controls in register TW5864_INDIR_AIN_0x06D */ | ||
1754 | /* | ||
1755 | * LAWMD Select u-Law/A-Law/PCM/SB data output format on ADATR and ADATM pin. | ||
1756 | * 0 PCM output (default) | ||
1757 | * 1 SB (Signed MSB bit in PCM data is inverted) output | ||
1758 | * 2 u-Law output | ||
1759 | * 3 A-Law output | ||
1760 | */ | ||
1761 | #define TW5864_INDIR_AIN_LAWMD_SHIFT 6 | ||
1762 | #define TW5864_INDIR_AIN_LAWMD (0x03 << 6) | ||
1763 | /* | ||
1764 | * Disable the mixing ratio value for all audio. | ||
1765 | * 0 Apply individual mixing ratio value for each audio (default) | ||
1766 | * 1 Apply nominal value for all audio commonly | ||
1767 | */ | ||
1768 | #define TW5864_INDIR_AIN_MIX_DERATIO BIT(5) | ||
1769 | /* | ||
1770 | * Enable the mute function for audio channel AINn when n is 0 to 3. It effects | ||
1771 | * only for mixing. When n = 4, it enable the mute function of the playback | ||
1772 | * audio input. It effects only for single chip or the last stage chip | ||
1773 | * 0 Normal | ||
1774 | * 1 Muted (default) | ||
1775 | */ | ||
1776 | #define TW5864_INDIR_AIN_MIX_MUTE 0x1f | ||
1777 | |||
1778 | /* Some registers skipped */ | ||
1779 | |||
1780 | #define TW5864_INDIR_AIN_0x0E3 0x0e3 | ||
1781 | /* Define controls in register TW5864_INDIR_AIN_0x0E3 */ | ||
1782 | /* | ||
1783 | * ADATP signal is coming from external ADPCM decoder, instead of on-chip ADPCM | ||
1784 | * decoder | ||
1785 | */ | ||
1786 | #define TW5864_INDIR_AIN_0x0E3_EXT_ADATP BIT(7) | ||
1787 | /* ACLKP output signal polarity inverse */ | ||
1788 | #define TW5864_INDIR_AIN_0x0E3_ACLKPPOLO BIT(6) | ||
1789 | /* | ||
1790 | * ACLKR input signal polarity inverse. | ||
1791 | * 0 Not inversed (Default) | ||
1792 | * 1 Inversed | ||
1793 | */ | ||
1794 | #define TW5864_INDIR_AIN_0x0E3_ACLKRPOL BIT(5) | ||
1795 | /* | ||
1796 | * ACLKP input signal polarity inverse. | ||
1797 | * 0 Not inversed (Default) | ||
1798 | * 1 Inversed | ||
1799 | */ | ||
1800 | #define TW5864_INDIR_AIN_0x0E3_ACLKPPOLI BIT(4) | ||
1801 | /* | ||
1802 | * ACKI [21:0] control automatic set up with AFMD registers | ||
1803 | * This mode is only effective when ACLKRMASTER=1 | ||
1804 | * 0 ACKI [21:0] registers set up ACKI control | ||
1805 | * 1 ACKI control is automatically set up by AFMD register values | ||
1806 | */ | ||
1807 | #define TW5864_INDIR_AIN_0x0E3_AFAUTO BIT(3) | ||
1808 | /* | ||
1809 | * AFAUTO control mode | ||
1810 | * 0 8kHz setting (Default) | ||
1811 | * 1 16kHz setting | ||
1812 | * 2 32kHz setting | ||
1813 | * 3 44.1kHz setting | ||
1814 | * 4 48kHz setting | ||
1815 | */ | ||
1816 | #define TW5864_INDIR_AIN_0x0E3_AFMD 0x07 | ||
1817 | |||
1818 | #define TW5864_INDIR_AIN_0x0E4 0x0e4 | ||
1819 | /* Define controls in register TW5864_INDIR_AIN_0x0ED */ | ||
1820 | /* | ||
1821 | * 8bit I2S Record output mode. | ||
1822 | * 0 L/R half length separated output (Default). | ||
1823 | * 1 One continuous packed output equal to DSP output format. | ||
1824 | */ | ||
1825 | #define TW5864_INDIR_AIN_0x0E4_I2S8MODE BIT(7) | ||
1826 | /* | ||
1827 | * Audio Clock Master ACLKR output wave format. | ||
1828 | * 0 High periods is one 27MHz clock period (default). | ||
1829 | * 1 Almost duty 50-50% clock output on ACLKR pin. If this mode is selected, two | ||
1830 | * times bigger number value need to be set up on the ACKI register. If | ||
1831 | * AFAUTO=1, ACKI control is automatically set up even if MASCKMD=1. | ||
1832 | */ | ||
1833 | #define TW5864_INDIR_AIN_0x0E4_MASCKMD BIT(6) | ||
1834 | /* Playback ACLKP/ASYNP/ADATP input data MSB-LSB swapping */ | ||
1835 | #define TW5864_INDIR_AIN_0x0E4_PBINSWAP BIT(5) | ||
1836 | /* | ||
1837 | * ASYNR input signal delay. | ||
1838 | * 0 No delay | ||
1839 | * 1 Add one 27MHz period delay in ASYNR signal input | ||
1840 | */ | ||
1841 | #define TW5864_INDIR_AIN_0x0E4_ASYNRDLY BIT(4) | ||
1842 | /* | ||
1843 | * ASYNP input signal delay. | ||
1844 | * 0 no delay | ||
1845 | * 1 add one 27MHz period delay in ASYNP signal input | ||
1846 | */ | ||
1847 | #define TW5864_INDIR_AIN_0x0E4_ASYNPDLY BIT(3) | ||
1848 | /* | ||
1849 | * ADATP input data delay by one ACLKP clock. | ||
1850 | * 0 No delay (Default). This is for I2S type 1T delay input interface. | ||
1851 | * 1 Add 1 ACLKP clock delay in ADATP input data. This is for left-justified | ||
1852 | * type 0T delay input interface. | ||
1853 | */ | ||
1854 | #define TW5864_INDIR_AIN_0x0E4_ADATPDLY BIT(2) | ||
1855 | /* | ||
1856 | * Select u-Law/A-Law/PCM/SB data input format on ADATP pin. | ||
1857 | * 0 PCM input (Default) | ||
1858 | * 1 SB (Signed MSB bit in PCM data is inverted) input | ||
1859 | * 2 u-Law input | ||
1860 | * 3 A-Law input | ||
1861 | */ | ||
1862 | #define TW5864_INDIR_AIN_0x0E4_INLAWMD 0x03 | ||
1863 | |||
1864 | /* | ||
1865 | * Enable state register updating and interrupt request of audio AIN5 detection | ||
1866 | * for each input | ||
1867 | */ | ||
1868 | #define TW5864_INDIR_AIN_A5DETENA 0x0e5 | ||
1869 | |||
1870 | /* Some registers skipped */ | ||
1871 | |||
1872 | /* | ||
1873 | * [7:3]: DEV_ID The TW5864 product ID code is 01000 | ||
1874 | * [2:0]: REV_ID The revision number is 0h | ||
1875 | */ | ||
1876 | #define TW5864_INDIR_ID 0x0fe | ||
1877 | |||
1878 | #define TW5864_INDIR_IN_PIC_WIDTH(channel) (0x200 + 4 * channel) | ||
1879 | #define TW5864_INDIR_IN_PIC_HEIGHT(channel) (0x201 + 4 * channel) | ||
1880 | #define TW5864_INDIR_OUT_PIC_WIDTH(channel) (0x202 + 4 * channel) | ||
1881 | #define TW5864_INDIR_OUT_PIC_HEIGHT(channel) (0x203 + 4 * channel) | ||
1882 | /* | ||
1883 | * Interrupt status register from the front-end. Write "1" to each bit to clear | ||
1884 | * the interrupt | ||
1885 | * 15:0 Motion detection interrupt for channel 0 ~ 15 | ||
1886 | * 31:16 Night detection interrupt for channel 0 ~ 15 | ||
1887 | * 47:32 Blind detection interrupt for channel 0 ~ 15 | ||
1888 | * 63:48 No video interrupt for channel 0 ~ 15 | ||
1889 | * 79:64 Line mode underflow interrupt for channel 0 ~ 15 | ||
1890 | * 95:80 Line mode overflow interrupt for channel 0 ~ 15 | ||
1891 | */ | ||
1892 | /* 0x2d0~0x2d7: [63:0] bits */ | ||
1893 | #define TW5864_INDIR_INTERRUPT1 0x2d0 | ||
1894 | /* 0x2e0~0x2e3: [95:64] bits */ | ||
1895 | #define TW5864_INDIR_INTERRUPT2 0x2e0 | ||
1896 | |||
1897 | /* | ||
1898 | * Interrupt mask register for interrupts in 0x2d0 ~ 0x2d7 | ||
1899 | * 15:0 Motion detection interrupt for channel 0 ~ 15 | ||
1900 | * 31:16 Night detection interrupt for channel 0 ~ 15 | ||
1901 | * 47:32 Blind detection interrupt for channel 0 ~ 15 | ||
1902 | * 63:48 No video interrupt for channel 0 ~ 15 | ||
1903 | * 79:64 Line mode underflow interrupt for channel 0 ~ 15 | ||
1904 | * 95:80 Line mode overflow interrupt for channel 0 ~ 15 | ||
1905 | */ | ||
1906 | /* 0x2d8~0x2df: [63:0] bits */ | ||
1907 | #define TW5864_INDIR_INTERRUPT_MASK1 0x2d8 | ||
1908 | /* 0x2e8~0x2eb: [95:64] bits */ | ||
1909 | #define TW5864_INDIR_INTERRUPT_MASK2 0x2e8 | ||
1910 | |||
1911 | /* [11:0]: Interrupt summary register for interrupts & interrupt mask from in | ||
1912 | * 0x2d0 ~ 0x2d7 and 0x2d8 ~ 0x2df | ||
1913 | * bit 0: interrupt occurs in 0x2d0 & 0x2d8 | ||
1914 | * bit 1: interrupt occurs in 0x2d1 & 0x2d9 | ||
1915 | * bit 2: interrupt occurs in 0x2d2 & 0x2da | ||
1916 | * bit 3: interrupt occurs in 0x2d3 & 0x2db | ||
1917 | * bit 4: interrupt occurs in 0x2d4 & 0x2dc | ||
1918 | * bit 5: interrupt occurs in 0x2d5 & 0x2dd | ||
1919 | * bit 6: interrupt occurs in 0x2d6 & 0x2de | ||
1920 | * bit 7: interrupt occurs in 0x2d7 & 0x2df | ||
1921 | * bit 8: interrupt occurs in 0x2e0 & 0x2e8 | ||
1922 | * bit 9: interrupt occurs in 0x2e1 & 0x2e9 | ||
1923 | * bit 10: interrupt occurs in 0x2e2 & 0x2ea | ||
1924 | * bit 11: interrupt occurs in 0x2e3 & 0x2eb | ||
1925 | */ | ||
1926 | #define TW5864_INDIR_INTERRUPT_SUMMARY 0x2f0 | ||
1927 | |||
1928 | /* Motion / Blind / Night Detection */ | ||
1929 | /* valid value for channel is [0:15] */ | ||
1930 | #define TW5864_INDIR_DETECTION_CTL0(channel) (0x300 + channel * 0x08) | ||
1931 | /* Define controls in register TW5864_INDIR_DETECTION_CTL0 */ | ||
1932 | /* | ||
1933 | * Disable the motion and blind detection. | ||
1934 | * 0 Enable motion and blind detection (default) | ||
1935 | * 1 Disable motion and blind detection | ||
1936 | */ | ||
1937 | #define TW5864_INDIR_DETECTION_CTL0_MD_DIS BIT(5) | ||
1938 | /* | ||
1939 | * Request to start motion detection on manual trigger mode | ||
1940 | * 0 None Operation (default) | ||
1941 | * 1 Request to start motion detection | ||
1942 | */ | ||
1943 | #define TW5864_INDIR_DETECTION_CTL0_MD_STRB BIT(3) | ||
1944 | /* | ||
1945 | * Select the trigger mode of motion detection | ||
1946 | * 0 Automatic trigger mode of motion detection (default) | ||
1947 | * 1 Manual trigger mode for motion detection | ||
1948 | */ | ||
1949 | #define TW5864_INDIR_DETECTION_CTL0_MD_STRB_EN BIT(2) | ||
1950 | /* | ||
1951 | * Define the threshold of cell for blind detection. | ||
1952 | * 0 Low threshold (More sensitive) (default) | ||
1953 | * : : | ||
1954 | * 3 High threshold (Less sensitive) | ||
1955 | */ | ||
1956 | #define TW5864_INDIR_DETECTION_CTL0_BD_CELSENS 0x03 | ||
1957 | |||
1958 | #define TW5864_INDIR_DETECTION_CTL1(channel) (0x301 + channel * 0x08) | ||
1959 | /* Define controls in register TW5864_INDIR_DETECTION_CTL1 */ | ||
1960 | /* | ||
1961 | * Control the temporal sensitivity of motion detector. | ||
1962 | * 0 More Sensitive (default) | ||
1963 | * : : | ||
1964 | * 15 Less Sensitive | ||
1965 | */ | ||
1966 | #define TW5864_INDIR_DETECTION_CTL1_MD_TMPSENS_SHIFT 4 | ||
1967 | #define TW5864_INDIR_DETECTION_CTL1_MD_TMPSENS (0x0f << 4) | ||
1968 | /* | ||
1969 | * Adjust the horizontal starting position for motion detection | ||
1970 | * 0 0 pixel (default) | ||
1971 | * : : | ||
1972 | * 15 15 pixels | ||
1973 | */ | ||
1974 | #define TW5864_INDIR_DETECTION_CTL1_MD_PIXEL_OS 0x0f | ||
1975 | |||
1976 | #define TW5864_INDIR_DETECTION_CTL2(channel) (0x302 + channel * 0x08) | ||
1977 | /* Define controls in register TW5864_INDIR_DETECTION_CTL2 */ | ||
1978 | /* | ||
1979 | * Control the updating time of reference field for motion detection. | ||
1980 | * 0 Update reference field every field (default) | ||
1981 | * 1 Update reference field according to MD_SPEED | ||
1982 | */ | ||
1983 | #define TW5864_INDIR_DETECTION_CTL2_MD_REFFLD BIT(7) | ||
1984 | /* | ||
1985 | * Select the field for motion detection. | ||
1986 | * 0 Detecting motion for only odd field (default) | ||
1987 | * 1 Detecting motion for only even field | ||
1988 | * 2 Detecting motion for any field | ||
1989 | * 3 Detecting motion for both odd and even field | ||
1990 | */ | ||
1991 | #define TW5864_INDIR_DETECTION_CTL2_MD_FIELD_SHIFT 5 | ||
1992 | #define TW5864_INDIR_DETECTION_CTL2_MD_FIELD (0x03 << 5) | ||
1993 | /* | ||
1994 | * Control the level sensitivity of motion detector. | ||
1995 | * 0 More sensitive (default) | ||
1996 | * : : | ||
1997 | * 15 Less sensitive | ||
1998 | */ | ||
1999 | #define TW5864_INDIR_DETECTION_CTL2_MD_LVSENS 0x1f | ||
2000 | |||
2001 | #define TW5864_INDIR_DETECTION_CTL3(channel) (0x303 + channel * 0x08) | ||
2002 | /* Define controls in register TW5864_INDIR_DETECTION_CTL3 */ | ||
2003 | /* | ||
2004 | * Define the threshold of sub-cell number for motion detection. | ||
2005 | * 0 Motion is detected if 1 sub-cell has motion (More sensitive) (default) | ||
2006 | * 1 Motion is detected if 2 sub-cells have motion | ||
2007 | * 2 Motion is detected if 3 sub-cells have motion | ||
2008 | * 3 Motion is detected if 4 sub-cells have motion (Less sensitive) | ||
2009 | */ | ||
2010 | #define TW5864_INDIR_DETECTION_CTL3_MD_CELSENS_SHIFT 6 | ||
2011 | #define TW5864_INDIR_DETECTION_CTL3_MD_CELSENS (0x03 << 6) | ||
2012 | /* | ||
2013 | * Control the velocity of motion detector. | ||
2014 | * Large value is suitable for slow motion detection. | ||
2015 | * In MD_DUAL_EN = 1, MD_SPEED should be limited to 0 ~ 31. | ||
2016 | * 0 1 field intervals (default) | ||
2017 | * 1 2 field intervals | ||
2018 | * : : | ||
2019 | * 61 62 field intervals | ||
2020 | * 62 63 field intervals | ||
2021 | * 63 Not supported | ||
2022 | */ | ||
2023 | #define TW5864_INDIR_DETECTION_CTL3_MD_SPEED 0x3f | ||
2024 | |||
2025 | #define TW5864_INDIR_DETECTION_CTL4(channel) (0x304 + channel * 0x08) | ||
2026 | /* Define controls in register TW5864_INDIR_DETECTION_CTL4 */ | ||
2027 | /* | ||
2028 | * Control the spatial sensitivity of motion detector. | ||
2029 | * 0 More Sensitive (default) | ||
2030 | * : : | ||
2031 | * 15 Less Sensitive | ||
2032 | */ | ||
2033 | #define TW5864_INDIR_DETECTION_CTL4_MD_SPSENS_SHIFT 4 | ||
2034 | #define TW5864_INDIR_DETECTION_CTL4_MD_SPSENS (0x0f << 4) | ||
2035 | /* | ||
2036 | * Define the threshold of level for blind detection. | ||
2037 | * 0 Low threshold (More sensitive) (default) | ||
2038 | * : : | ||
2039 | * 15 High threshold (Less sensitive) | ||
2040 | */ | ||
2041 | #define TW5864_INDIR_DETECTION_CTL4_BD_LVSENS 0x0f | ||
2042 | |||
2043 | #define TW5864_INDIR_DETECTION_CTL5(channel) (0x305 + channel * 0x08) | ||
2044 | /* | ||
2045 | * Define the threshold of temporal sensitivity for night detection. | ||
2046 | * 0 Low threshold (More sensitive) (default) | ||
2047 | * : : | ||
2048 | * 15 High threshold (Less sensitive) | ||
2049 | */ | ||
2050 | #define TW5864_INDIR_DETECTION_CTL5_ND_TMPSENS_SHIFT 4 | ||
2051 | #define TW5864_INDIR_DETECTION_CTL5_ND_TMPSENS (0x0f << 4) | ||
2052 | /* | ||
2053 | * Define the threshold of level for night detection. | ||
2054 | * 0 Low threshold (More sensitive) (default) | ||
2055 | * : : | ||
2056 | * 3 High threshold (Less sensitive) | ||
2057 | */ | ||
2058 | #define TW5864_INDIR_DETECTION_CTL5_ND_LVSENS 0x0f | ||
2059 | |||
2060 | /* | ||
2061 | * [11:0] The base address of the motion detection buffer. This address is in | ||
2062 | * unit of 64K bytes. The generated DDR address will be {MD_BASE_ADDR, | ||
2063 | * 16"h0000}. The default value should be 12"h000 | ||
2064 | */ | ||
2065 | #define TW5864_INDIR_MD_BASE_ADDR 0x380 | ||
2066 | |||
2067 | /* | ||
2068 | * This controls the channel of the motion detection result shown in register | ||
2069 | * 0x3a0 ~ 0x3b7. Before reading back motion result, always set this first. | ||
2070 | */ | ||
2071 | #define TW5864_INDIR_RGR_MOTION_SEL 0x382 | ||
2072 | |||
2073 | /* [15:0] MD strobe has been performed at channel n (read only) */ | ||
2074 | #define TW5864_INDIR_MD_STRB 0x386 | ||
2075 | /* NO_VIDEO Detected from channel n (read only) */ | ||
2076 | #define TW5864_INDIR_NOVID_DET 0x388 | ||
2077 | /* Motion Detected from channel n (read only) */ | ||
2078 | #define TW5864_INDIR_MD_DET 0x38a | ||
2079 | /* Blind Detected from channel n (read only) */ | ||
2080 | #define TW5864_INDIR_BD_DET 0x38c | ||
2081 | /* Night Detected from channel n (read only) */ | ||
2082 | #define TW5864_INDIR_ND_DET 0x38e | ||
2083 | |||
2084 | /* 192 bit motion flag of the channel specified by RGR_MOTION_SEL in 0x382 */ | ||
2085 | #define TW5864_INDIR_MOTION_FLAG 0x3a0 | ||
2086 | #define TW5864_INDIR_MOTION_FLAG_BYTE_COUNT 24 | ||
2087 | |||
2088 | /* | ||
2089 | * [9:0] The motion cell count of a specific channel selected by 0x382. This is | ||
2090 | * for DI purpose | ||
2091 | */ | ||
2092 | #define TW5864_INDIR_MD_DI_CNT 0x3b8 | ||
2093 | /* The motion detection cell sensitivity for DI purpose */ | ||
2094 | #define TW5864_INDIR_MD_DI_CELLSENS 0x3ba | ||
2095 | /* The motion detection threshold level for DI purpose */ | ||
2096 | #define TW5864_INDIR_MD_DI_LVSENS 0x3bb | ||
2097 | |||
2098 | /* 192 bit motion mask of the channel specified by MASK_CH_SEL in 0x3fe */ | ||
2099 | #define TW5864_INDIR_MOTION_MASK 0x3e0 | ||
2100 | #define TW5864_INDIR_MOTION_MASK_BYTE_COUNT 24 | ||
2101 | |||
2102 | /* [4:0] The channel selection to access masks in 0x3e0 ~ 0x3f7 */ | ||
2103 | #define TW5864_INDIR_MASK_CH_SEL 0x3fe | ||
2104 | |||
2105 | /* Clock PLL / Analog IP Control */ | ||
2106 | /* Some registers skipped */ | ||
2107 | |||
2108 | #define TW5864_INDIR_DDRA_DLL_DQS_SEL0 0xee6 | ||
2109 | #define TW5864_INDIR_DDRA_DLL_DQS_SEL1 0xee7 | ||
2110 | #define TW5864_INDIR_DDRA_DLL_CLK90_SEL 0xee8 | ||
2111 | #define TW5864_INDIR_DDRA_DLL_TEST_SEL_AND_TAP_S 0xee9 | ||
2112 | |||
2113 | #define TW5864_INDIR_DDRB_DLL_DQS_SEL0 0xeeb | ||
2114 | #define TW5864_INDIR_DDRB_DLL_DQS_SEL1 0xeec | ||
2115 | #define TW5864_INDIR_DDRB_DLL_CLK90_SEL 0xeed | ||
2116 | #define TW5864_INDIR_DDRB_DLL_TEST_SEL_AND_TAP_S 0xeee | ||
2117 | |||
2118 | #define TW5864_INDIR_RESET 0xef0 | ||
2119 | #define TW5864_INDIR_RESET_VD BIT(7) | ||
2120 | #define TW5864_INDIR_RESET_DLL BIT(6) | ||
2121 | #define TW5864_INDIR_RESET_MUX_CORE BIT(5) | ||
2122 | |||
2123 | #define TW5864_INDIR_PV_VD_CK_POL 0xefd | ||
2124 | #define TW5864_INDIR_PV_VD_CK_POL_PV(channel) BIT(channel) | ||
2125 | #define TW5864_INDIR_PV_VD_CK_POL_VD(channel) BIT(channel + 4) | ||
2126 | |||
2127 | #define TW5864_INDIR_CLK0_SEL 0xefe | ||
2128 | #define TW5864_INDIR_CLK0_SEL_VD_SHIFT 0 | ||
2129 | #define TW5864_INDIR_CLK0_SEL_VD_MASK 0x3 | ||
2130 | #define TW5864_INDIR_CLK0_SEL_PV_SHIFT 2 | ||
2131 | #define TW5864_INDIR_CLK0_SEL_PV_MASK (0x3 << 2) | ||
2132 | #define TW5864_INDIR_CLK0_SEL_PV2_SHIFT 4 | ||
2133 | #define TW5864_INDIR_CLK0_SEL_PV2_MASK (0x3 << 4) | ||
diff --git a/drivers/media/pci/tw5864/tw5864-util.c b/drivers/media/pci/tw5864/tw5864-util.c new file mode 100644 index 000000000000..771eef235755 --- /dev/null +++ b/drivers/media/pci/tw5864/tw5864-util.c | |||
@@ -0,0 +1,37 @@ | |||
1 | #include "tw5864.h" | ||
2 | |||
3 | void tw5864_indir_writeb(struct tw5864_dev *dev, u16 addr, u8 data) | ||
4 | { | ||
5 | int retries = 30000; | ||
6 | |||
7 | while (tw_readl(TW5864_IND_CTL) & BIT(31) && --retries) | ||
8 | ; | ||
9 | if (!retries) | ||
10 | dev_err(&dev->pci->dev, | ||
11 | "tw_indir_writel() retries exhausted before writing\n"); | ||
12 | |||
13 | tw_writel(TW5864_IND_DATA, data); | ||
14 | tw_writel(TW5864_IND_CTL, addr << 2 | TW5864_RW | TW5864_ENABLE); | ||
15 | } | ||
16 | |||
17 | u8 tw5864_indir_readb(struct tw5864_dev *dev, u16 addr) | ||
18 | { | ||
19 | int retries = 30000; | ||
20 | |||
21 | while (tw_readl(TW5864_IND_CTL) & BIT(31) && --retries) | ||
22 | ; | ||
23 | if (!retries) | ||
24 | dev_err(&dev->pci->dev, | ||
25 | "tw_indir_readl() retries exhausted before reading\n"); | ||
26 | |||
27 | tw_writel(TW5864_IND_CTL, addr << 2 | TW5864_ENABLE); | ||
28 | |||
29 | retries = 30000; | ||
30 | while (tw_readl(TW5864_IND_CTL) & BIT(31) && --retries) | ||
31 | ; | ||
32 | if (!retries) | ||
33 | dev_err(&dev->pci->dev, | ||
34 | "tw_indir_readl() retries exhausted at reading\n"); | ||
35 | |||
36 | return tw_readl(TW5864_IND_DATA); | ||
37 | } | ||
diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c new file mode 100644 index 000000000000..652a059b2e0a --- /dev/null +++ b/drivers/media/pci/tw5864/tw5864-video.c | |||
@@ -0,0 +1,1510 @@ | |||
1 | /* | ||
2 | * TW5864 driver - video encoding functions | ||
3 | * | ||
4 | * Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <media/v4l2-common.h> | ||
19 | #include <media/v4l2-event.h> | ||
20 | #include <media/videobuf2-dma-contig.h> | ||
21 | |||
22 | #include "tw5864.h" | ||
23 | #include "tw5864-reg.h" | ||
24 | |||
25 | #define QUANTIZATION_TABLE_LEN 96 | ||
26 | #define VLC_LOOKUP_TABLE_LEN 1024 | ||
27 | |||
28 | static const u16 forward_quantization_table[QUANTIZATION_TABLE_LEN] = { | ||
29 | 0x3333, 0x1f82, 0x3333, 0x1f82, 0x1f82, 0x147b, 0x1f82, 0x147b, | ||
30 | 0x3333, 0x1f82, 0x3333, 0x1f82, 0x1f82, 0x147b, 0x1f82, 0x147b, | ||
31 | 0x2e8c, 0x1d42, 0x2e8c, 0x1d42, 0x1d42, 0x1234, 0x1d42, 0x1234, | ||
32 | 0x2e8c, 0x1d42, 0x2e8c, 0x1d42, 0x1d42, 0x1234, 0x1d42, 0x1234, | ||
33 | 0x2762, 0x199a, 0x2762, 0x199a, 0x199a, 0x1062, 0x199a, 0x1062, | ||
34 | 0x2762, 0x199a, 0x2762, 0x199a, 0x199a, 0x1062, 0x199a, 0x1062, | ||
35 | 0x2492, 0x16c1, 0x2492, 0x16c1, 0x16c1, 0x0e3f, 0x16c1, 0x0e3f, | ||
36 | 0x2492, 0x16c1, 0x2492, 0x16c1, 0x16c1, 0x0e3f, 0x16c1, 0x0e3f, | ||
37 | 0x2000, 0x147b, 0x2000, 0x147b, 0x147b, 0x0d1b, 0x147b, 0x0d1b, | ||
38 | 0x2000, 0x147b, 0x2000, 0x147b, 0x147b, 0x0d1b, 0x147b, 0x0d1b, | ||
39 | 0x1c72, 0x11cf, 0x1c72, 0x11cf, 0x11cf, 0x0b4d, 0x11cf, 0x0b4d, | ||
40 | 0x1c72, 0x11cf, 0x1c72, 0x11cf, 0x11cf, 0x0b4d, 0x11cf, 0x0b4d | ||
41 | }; | ||
42 | |||
43 | static const u16 inverse_quantization_table[QUANTIZATION_TABLE_LEN] = { | ||
44 | 0x800a, 0x800d, 0x800a, 0x800d, 0x800d, 0x8010, 0x800d, 0x8010, | ||
45 | 0x800a, 0x800d, 0x800a, 0x800d, 0x800d, 0x8010, 0x800d, 0x8010, | ||
46 | 0x800b, 0x800e, 0x800b, 0x800e, 0x800e, 0x8012, 0x800e, 0x8012, | ||
47 | 0x800b, 0x800e, 0x800b, 0x800e, 0x800e, 0x8012, 0x800e, 0x8012, | ||
48 | 0x800d, 0x8010, 0x800d, 0x8010, 0x8010, 0x8014, 0x8010, 0x8014, | ||
49 | 0x800d, 0x8010, 0x800d, 0x8010, 0x8010, 0x8014, 0x8010, 0x8014, | ||
50 | 0x800e, 0x8012, 0x800e, 0x8012, 0x8012, 0x8017, 0x8012, 0x8017, | ||
51 | 0x800e, 0x8012, 0x800e, 0x8012, 0x8012, 0x8017, 0x8012, 0x8017, | ||
52 | 0x8010, 0x8014, 0x8010, 0x8014, 0x8014, 0x8019, 0x8014, 0x8019, | ||
53 | 0x8010, 0x8014, 0x8010, 0x8014, 0x8014, 0x8019, 0x8014, 0x8019, | ||
54 | 0x8012, 0x8017, 0x8012, 0x8017, 0x8017, 0x801d, 0x8017, 0x801d, | ||
55 | 0x8012, 0x8017, 0x8012, 0x8017, 0x8017, 0x801d, 0x8017, 0x801d | ||
56 | }; | ||
57 | |||
58 | static const u16 encoder_vlc_lookup_table[VLC_LOOKUP_TABLE_LEN] = { | ||
59 | 0x011, 0x000, 0x000, 0x000, 0x065, 0x021, 0x000, 0x000, 0x087, 0x064, | ||
60 | 0x031, 0x000, 0x097, 0x086, 0x075, 0x053, 0x0a7, 0x096, 0x085, 0x063, | ||
61 | 0x0b7, 0x0a6, 0x095, 0x074, 0x0df, 0x0b6, 0x0a5, 0x084, 0x0db, 0x0de, | ||
62 | 0x0b5, 0x094, 0x0d8, 0x0da, 0x0dd, 0x0a4, 0x0ef, 0x0ee, 0x0d9, 0x0b4, | ||
63 | 0x0eb, 0x0ea, 0x0ed, 0x0dc, 0x0ff, 0x0fe, 0x0e9, 0x0ec, 0x0fb, 0x0fa, | ||
64 | 0x0fd, 0x0e8, 0x10f, 0x0f1, 0x0f9, 0x0fc, 0x10b, 0x10e, 0x10d, 0x0f8, | ||
65 | 0x107, 0x10a, 0x109, 0x10c, 0x104, 0x106, 0x105, 0x108, 0x023, 0x000, | ||
66 | 0x000, 0x000, 0x06b, 0x022, 0x000, 0x000, 0x067, 0x057, 0x033, 0x000, | ||
67 | 0x077, 0x06a, 0x069, 0x045, 0x087, 0x066, 0x065, 0x044, 0x084, 0x076, | ||
68 | 0x075, 0x056, 0x097, 0x086, 0x085, 0x068, 0x0bf, 0x096, 0x095, 0x064, | ||
69 | 0x0bb, 0x0be, 0x0bd, 0x074, 0x0cf, 0x0ba, 0x0b9, 0x094, 0x0cb, 0x0ce, | ||
70 | 0x0cd, 0x0bc, 0x0c8, 0x0ca, 0x0c9, 0x0b8, 0x0df, 0x0de, 0x0dd, 0x0cc, | ||
71 | 0x0db, 0x0da, 0x0d9, 0x0dc, 0x0d7, 0x0eb, 0x0d6, 0x0d8, 0x0e9, 0x0e8, | ||
72 | 0x0ea, 0x0d1, 0x0e7, 0x0e6, 0x0e5, 0x0e4, 0x04f, 0x000, 0x000, 0x000, | ||
73 | 0x06f, 0x04e, 0x000, 0x000, 0x06b, 0x05f, 0x04d, 0x000, 0x068, 0x05c, | ||
74 | 0x05e, 0x04c, 0x07f, 0x05a, 0x05b, 0x04b, 0x07b, 0x058, 0x059, 0x04a, | ||
75 | 0x079, 0x06e, 0x06d, 0x049, 0x078, 0x06a, 0x069, 0x048, 0x08f, 0x07e, | ||
76 | 0x07d, 0x05d, 0x08b, 0x08e, 0x07a, 0x06c, 0x09f, 0x08a, 0x08d, 0x07c, | ||
77 | 0x09b, 0x09e, 0x089, 0x08c, 0x098, 0x09a, 0x09d, 0x088, 0x0ad, 0x097, | ||
78 | 0x099, 0x09c, 0x0a9, 0x0ac, 0x0ab, 0x0aa, 0x0a5, 0x0a8, 0x0a7, 0x0a6, | ||
79 | 0x0a1, 0x0a4, 0x0a3, 0x0a2, 0x021, 0x000, 0x000, 0x000, 0x067, 0x011, | ||
80 | 0x000, 0x000, 0x064, 0x066, 0x031, 0x000, 0x063, 0x073, 0x072, 0x065, | ||
81 | 0x062, 0x083, 0x082, 0x070, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
82 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
83 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
84 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
85 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
86 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
87 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
88 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
89 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
90 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
91 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
92 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
93 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
94 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
95 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
96 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
97 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
98 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
99 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
100 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
101 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
102 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
103 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
104 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
105 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
106 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
107 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
108 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
109 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
110 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
111 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x011, 0x010, | ||
112 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
113 | 0x000, 0x000, 0x000, 0x000, 0x011, 0x021, 0x020, 0x000, 0x000, 0x000, | ||
114 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
115 | 0x023, 0x022, 0x021, 0x020, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
116 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x023, 0x022, 0x021, 0x031, | ||
117 | 0x030, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
118 | 0x000, 0x000, 0x023, 0x022, 0x033, 0x032, 0x031, 0x030, 0x000, 0x000, | ||
119 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x023, 0x030, | ||
120 | 0x031, 0x033, 0x032, 0x035, 0x034, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
121 | 0x000, 0x000, 0x000, 0x000, 0x037, 0x036, 0x035, 0x034, 0x033, 0x032, | ||
122 | 0x031, 0x041, 0x051, 0x061, 0x071, 0x081, 0x091, 0x0a1, 0x0b1, 0x000, | ||
123 | 0x002, 0x000, 0x0e4, 0x011, 0x0f4, 0x002, 0x024, 0x003, 0x005, 0x012, | ||
124 | 0x034, 0x013, 0x065, 0x024, 0x013, 0x063, 0x015, 0x022, 0x075, 0x034, | ||
125 | 0x044, 0x023, 0x023, 0x073, 0x054, 0x033, 0x033, 0x004, 0x043, 0x014, | ||
126 | 0x011, 0x043, 0x014, 0x001, 0x025, 0x015, 0x035, 0x025, 0x064, 0x055, | ||
127 | 0x045, 0x035, 0x074, 0x065, 0x085, 0x0d5, 0x012, 0x095, 0x055, 0x045, | ||
128 | 0x095, 0x0e5, 0x084, 0x075, 0x022, 0x0a5, 0x094, 0x085, 0x032, 0x0b5, | ||
129 | 0x003, 0x0c5, 0x001, 0x044, 0x0a5, 0x032, 0x0b5, 0x094, 0x0c5, 0x0a4, | ||
130 | 0x0a4, 0x054, 0x0d5, 0x0b4, 0x0b4, 0x064, 0x0f5, 0x0f5, 0x053, 0x0d4, | ||
131 | 0x0e5, 0x0c4, 0x105, 0x105, 0x0c4, 0x074, 0x063, 0x0e4, 0x0d4, 0x084, | ||
132 | 0x073, 0x0f4, 0x004, 0x005, 0x000, 0x053, 0x000, 0x000, 0x000, 0x000, | ||
133 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
134 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
135 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
136 | 0x000, 0x000, 0x011, 0x021, 0x031, 0x030, 0x011, 0x021, 0x020, 0x000, | ||
137 | 0x011, 0x010, 0x000, 0x000, 0x011, 0x033, 0x032, 0x043, 0x042, 0x053, | ||
138 | 0x052, 0x063, 0x062, 0x073, 0x072, 0x083, 0x082, 0x093, 0x092, 0x091, | ||
139 | 0x037, 0x036, 0x035, 0x034, 0x033, 0x045, 0x044, 0x043, 0x042, 0x053, | ||
140 | 0x052, 0x063, 0x062, 0x061, 0x060, 0x000, 0x045, 0x037, 0x036, 0x035, | ||
141 | 0x044, 0x043, 0x034, 0x033, 0x042, 0x053, 0x052, 0x061, 0x051, 0x060, | ||
142 | 0x000, 0x000, 0x053, 0x037, 0x045, 0x044, 0x036, 0x035, 0x034, 0x043, | ||
143 | 0x033, 0x042, 0x052, 0x051, 0x050, 0x000, 0x000, 0x000, 0x045, 0x044, | ||
144 | 0x043, 0x037, 0x036, 0x035, 0x034, 0x033, 0x042, 0x051, 0x041, 0x050, | ||
145 | 0x000, 0x000, 0x000, 0x000, 0x061, 0x051, 0x037, 0x036, 0x035, 0x034, | ||
146 | 0x033, 0x032, 0x041, 0x031, 0x060, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
147 | 0x061, 0x051, 0x035, 0x034, 0x033, 0x023, 0x032, 0x041, 0x031, 0x060, | ||
148 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x061, 0x041, 0x051, 0x033, | ||
149 | 0x023, 0x022, 0x032, 0x031, 0x060, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
150 | 0x000, 0x000, 0x061, 0x060, 0x041, 0x023, 0x022, 0x031, 0x021, 0x051, | ||
151 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x051, 0x050, | ||
152 | 0x031, 0x023, 0x022, 0x021, 0x041, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
153 | 0x000, 0x000, 0x000, 0x000, 0x040, 0x041, 0x031, 0x032, 0x011, 0x033, | ||
154 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
155 | 0x040, 0x041, 0x021, 0x011, 0x031, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
156 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x030, 0x031, 0x011, 0x021, | ||
157 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
158 | 0x000, 0x000, 0x020, 0x021, 0x011, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
159 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x010, 0x011, | ||
160 | 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, | ||
161 | 0x000, 0x000, 0x000, 0x000 | ||
162 | }; | ||
163 | |||
164 | static const unsigned int lambda_lookup_table[] = { | ||
165 | 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, | ||
166 | 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, | ||
167 | 0x0040, 0x0040, 0x0040, 0x0040, 0x0060, 0x0060, 0x0060, 0x0080, | ||
168 | 0x0080, 0x0080, 0x00a0, 0x00c0, 0x00c0, 0x00e0, 0x0100, 0x0120, | ||
169 | 0x0140, 0x0160, 0x01a0, 0x01c0, 0x0200, 0x0240, 0x0280, 0x02e0, | ||
170 | 0x0320, 0x03a0, 0x0400, 0x0480, 0x0500, 0x05a0, 0x0660, 0x0720, | ||
171 | 0x0800, 0x0900, 0x0a20, 0x0b60 | ||
172 | }; | ||
173 | |||
174 | static const unsigned int intra4x4_lambda3[] = { | ||
175 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
176 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
177 | 2, 2, 2, 2, 3, 3, 3, 4, | ||
178 | 4, 4, 5, 6, 6, 7, 8, 9, | ||
179 | 10, 11, 13, 14, 16, 18, 20, 23, | ||
180 | 25, 29, 32, 36, 40, 45, 51, 57, | ||
181 | 64, 72, 81, 91 | ||
182 | }; | ||
183 | |||
184 | static v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std); | ||
185 | static enum tw5864_vid_std tw5864_from_v4l2_std(v4l2_std_id v4l2_std); | ||
186 | |||
187 | static void tw5864_handle_frame_task(unsigned long data); | ||
188 | static void tw5864_handle_frame(struct tw5864_h264_frame *frame); | ||
189 | static void tw5864_frame_interval_set(struct tw5864_input *input); | ||
190 | |||
191 | static int tw5864_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, | ||
192 | unsigned int *num_planes, unsigned int sizes[], | ||
193 | struct device *alloc_ctxs[]) | ||
194 | { | ||
195 | if (*num_planes) | ||
196 | return sizes[0] < H264_VLC_BUF_SIZE ? -EINVAL : 0; | ||
197 | |||
198 | sizes[0] = H264_VLC_BUF_SIZE; | ||
199 | *num_planes = 1; | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static void tw5864_buf_queue(struct vb2_buffer *vb) | ||
205 | { | ||
206 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
207 | struct vb2_queue *vq = vb->vb2_queue; | ||
208 | struct tw5864_input *dev = vb2_get_drv_priv(vq); | ||
209 | struct tw5864_buf *buf = container_of(vbuf, struct tw5864_buf, vb); | ||
210 | unsigned long flags; | ||
211 | |||
212 | spin_lock_irqsave(&dev->slock, flags); | ||
213 | list_add_tail(&buf->list, &dev->active); | ||
214 | spin_unlock_irqrestore(&dev->slock, flags); | ||
215 | } | ||
216 | |||
217 | static int tw5864_input_std_get(struct tw5864_input *input, | ||
218 | enum tw5864_vid_std *std) | ||
219 | { | ||
220 | struct tw5864_dev *dev = input->root; | ||
221 | u8 std_reg = tw_indir_readb(TW5864_INDIR_VIN_E(input->nr)); | ||
222 | |||
223 | *std = (std_reg & 0x70) >> 4; | ||
224 | |||
225 | if (std_reg & 0x80) { | ||
226 | dev_dbg(&dev->pci->dev, | ||
227 | "Video format detection is in progress, please wait\n"); | ||
228 | return -EAGAIN; | ||
229 | } | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int tw5864_enable_input(struct tw5864_input *input) | ||
235 | { | ||
236 | struct tw5864_dev *dev = input->root; | ||
237 | int nr = input->nr; | ||
238 | unsigned long flags; | ||
239 | int d1_width = 720; | ||
240 | int d1_height; | ||
241 | int frame_width_bus_value = 0; | ||
242 | int frame_height_bus_value = 0; | ||
243 | int reg_frame_bus = 0x1c; | ||
244 | int fmt_reg_value = 0; | ||
245 | int downscale_enabled = 0; | ||
246 | |||
247 | dev_dbg(&dev->pci->dev, "Enabling channel %d\n", nr); | ||
248 | |||
249 | input->frame_seqno = 0; | ||
250 | input->frame_gop_seqno = 0; | ||
251 | input->h264_idr_pic_id = 0; | ||
252 | |||
253 | input->reg_dsp_qp = input->qp; | ||
254 | input->reg_dsp_ref_mvp_lambda = lambda_lookup_table[input->qp]; | ||
255 | input->reg_dsp_i4x4_weight = intra4x4_lambda3[input->qp]; | ||
256 | input->reg_emu = TW5864_EMU_EN_LPF | TW5864_EMU_EN_BHOST | ||
257 | | TW5864_EMU_EN_SEN | TW5864_EMU_EN_ME | TW5864_EMU_EN_DDR; | ||
258 | input->reg_dsp = nr /* channel id */ | ||
259 | | TW5864_DSP_CHROM_SW | ||
260 | | ((0xa << 8) & TW5864_DSP_MB_DELAY) | ||
261 | ; | ||
262 | |||
263 | input->resolution = D1; | ||
264 | |||
265 | d1_height = (input->std == STD_NTSC) ? 480 : 576; | ||
266 | |||
267 | input->width = d1_width; | ||
268 | input->height = d1_height; | ||
269 | |||
270 | input->reg_interlacing = 0x4; | ||
271 | |||
272 | switch (input->resolution) { | ||
273 | case D1: | ||
274 | frame_width_bus_value = 0x2cf; | ||
275 | frame_height_bus_value = input->height - 1; | ||
276 | reg_frame_bus = 0x1c; | ||
277 | fmt_reg_value = 0; | ||
278 | downscale_enabled = 0; | ||
279 | input->reg_dsp_codec |= TW5864_CIF_MAP_MD | TW5864_HD1_MAP_MD; | ||
280 | input->reg_emu |= TW5864_DSP_FRAME_TYPE_D1; | ||
281 | input->reg_interlacing = TW5864_DI_EN | TW5864_DSP_INTER_ST; | ||
282 | |||
283 | tw_setl(TW5864_FULL_HALF_FLAG, 1 << nr); | ||
284 | break; | ||
285 | case HD1: | ||
286 | input->height /= 2; | ||
287 | input->width /= 2; | ||
288 | frame_width_bus_value = 0x2cf; | ||
289 | frame_height_bus_value = input->height * 2 - 1; | ||
290 | reg_frame_bus = 0x1c; | ||
291 | fmt_reg_value = 0; | ||
292 | downscale_enabled = 0; | ||
293 | input->reg_dsp_codec |= TW5864_HD1_MAP_MD; | ||
294 | input->reg_emu |= TW5864_DSP_FRAME_TYPE_D1; | ||
295 | |||
296 | tw_clearl(TW5864_FULL_HALF_FLAG, 1 << nr); | ||
297 | |||
298 | break; | ||
299 | case CIF: | ||
300 | input->height /= 4; | ||
301 | input->width /= 2; | ||
302 | frame_width_bus_value = 0x15f; | ||
303 | frame_height_bus_value = input->height * 2 - 1; | ||
304 | reg_frame_bus = 0x07; | ||
305 | fmt_reg_value = 1; | ||
306 | downscale_enabled = 1; | ||
307 | input->reg_dsp_codec |= TW5864_CIF_MAP_MD; | ||
308 | |||
309 | tw_clearl(TW5864_FULL_HALF_FLAG, 1 << nr); | ||
310 | break; | ||
311 | case QCIF: | ||
312 | input->height /= 4; | ||
313 | input->width /= 4; | ||
314 | frame_width_bus_value = 0x15f; | ||
315 | frame_height_bus_value = input->height * 2 - 1; | ||
316 | reg_frame_bus = 0x07; | ||
317 | fmt_reg_value = 1; | ||
318 | downscale_enabled = 1; | ||
319 | input->reg_dsp_codec |= TW5864_CIF_MAP_MD; | ||
320 | |||
321 | tw_clearl(TW5864_FULL_HALF_FLAG, 1 << nr); | ||
322 | break; | ||
323 | } | ||
324 | |||
325 | /* analog input width / 4 */ | ||
326 | tw_indir_writeb(TW5864_INDIR_IN_PIC_WIDTH(nr), d1_width / 4); | ||
327 | tw_indir_writeb(TW5864_INDIR_IN_PIC_HEIGHT(nr), d1_height / 4); | ||
328 | |||
329 | /* output width / 4 */ | ||
330 | tw_indir_writeb(TW5864_INDIR_OUT_PIC_WIDTH(nr), input->width / 4); | ||
331 | tw_indir_writeb(TW5864_INDIR_OUT_PIC_HEIGHT(nr), input->height / 4); | ||
332 | |||
333 | tw_writel(TW5864_DSP_PIC_MAX_MB, | ||
334 | ((input->width / 16) << 8) | (input->height / 16)); | ||
335 | |||
336 | tw_writel(TW5864_FRAME_WIDTH_BUS_A(nr), | ||
337 | frame_width_bus_value); | ||
338 | tw_writel(TW5864_FRAME_WIDTH_BUS_B(nr), | ||
339 | frame_width_bus_value); | ||
340 | tw_writel(TW5864_FRAME_HEIGHT_BUS_A(nr), | ||
341 | frame_height_bus_value); | ||
342 | tw_writel(TW5864_FRAME_HEIGHT_BUS_B(nr), | ||
343 | (frame_height_bus_value + 1) / 2 - 1); | ||
344 | |||
345 | tw5864_frame_interval_set(input); | ||
346 | |||
347 | if (downscale_enabled) | ||
348 | tw_setl(TW5864_H264EN_CH_DNS, 1 << nr); | ||
349 | |||
350 | tw_mask_shift_writel(TW5864_H264EN_CH_FMT_REG1, 0x3, 2 * nr, | ||
351 | fmt_reg_value); | ||
352 | |||
353 | tw_mask_shift_writel((nr < 2 | ||
354 | ? TW5864_H264EN_RATE_MAX_LINE_REG1 | ||
355 | : TW5864_H264EN_RATE_MAX_LINE_REG2), | ||
356 | 0x1f, 5 * (nr % 2), | ||
357 | input->std == STD_NTSC ? 29 : 24); | ||
358 | |||
359 | tw_mask_shift_writel((nr < 2) ? TW5864_FRAME_BUS1 : | ||
360 | TW5864_FRAME_BUS2, 0xff, (nr % 2) * 8, | ||
361 | reg_frame_bus); | ||
362 | |||
363 | spin_lock_irqsave(&dev->slock, flags); | ||
364 | input->enabled = 1; | ||
365 | spin_unlock_irqrestore(&dev->slock, flags); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | void tw5864_request_encoded_frame(struct tw5864_input *input) | ||
371 | { | ||
372 | struct tw5864_dev *dev = input->root; | ||
373 | u32 enc_buf_id_new; | ||
374 | |||
375 | tw_setl(TW5864_DSP_CODEC, TW5864_CIF_MAP_MD | TW5864_HD1_MAP_MD); | ||
376 | tw_writel(TW5864_EMU, input->reg_emu); | ||
377 | tw_writel(TW5864_INTERLACING, input->reg_interlacing); | ||
378 | tw_writel(TW5864_DSP, input->reg_dsp); | ||
379 | |||
380 | tw_writel(TW5864_DSP_QP, input->reg_dsp_qp); | ||
381 | tw_writel(TW5864_DSP_REF_MVP_LAMBDA, input->reg_dsp_ref_mvp_lambda); | ||
382 | tw_writel(TW5864_DSP_I4x4_WEIGHT, input->reg_dsp_i4x4_weight); | ||
383 | tw_mask_shift_writel(TW5864_DSP_INTRA_MODE, TW5864_DSP_INTRA_MODE_MASK, | ||
384 | TW5864_DSP_INTRA_MODE_SHIFT, | ||
385 | TW5864_DSP_INTRA_MODE_16x16); | ||
386 | |||
387 | if (input->frame_gop_seqno == 0) { | ||
388 | /* Produce I-frame */ | ||
389 | tw_writel(TW5864_MOTION_SEARCH_ETC, TW5864_INTRA_EN); | ||
390 | input->h264_idr_pic_id++; | ||
391 | input->h264_idr_pic_id &= TW5864_DSP_REF_FRM; | ||
392 | } else { | ||
393 | /* Produce P-frame */ | ||
394 | tw_writel(TW5864_MOTION_SEARCH_ETC, TW5864_INTRA_EN | | ||
395 | TW5864_ME_EN | BIT(5) /* SRCH_OPT default */); | ||
396 | } | ||
397 | tw5864_prepare_frame_headers(input); | ||
398 | tw_writel(TW5864_VLC, | ||
399 | TW5864_VLC_PCI_SEL | | ||
400 | ((input->tail_nb_bits + 24) << TW5864_VLC_BIT_ALIGN_SHIFT) | | ||
401 | input->reg_dsp_qp); | ||
402 | |||
403 | enc_buf_id_new = tw_mask_shift_readl(TW5864_ENC_BUF_PTR_REC1, 0x3, | ||
404 | 2 * input->nr); | ||
405 | tw_writel(TW5864_DSP_ENC_ORG_PTR_REG, | ||
406 | enc_buf_id_new << TW5864_DSP_ENC_ORG_PTR_SHIFT); | ||
407 | tw_writel(TW5864_DSP_ENC_REC, | ||
408 | enc_buf_id_new << 12 | ((enc_buf_id_new + 3) & 3)); | ||
409 | |||
410 | tw_writel(TW5864_SLICE, TW5864_START_NSLICE); | ||
411 | tw_writel(TW5864_SLICE, 0); | ||
412 | } | ||
413 | |||
414 | static int tw5864_disable_input(struct tw5864_input *input) | ||
415 | { | ||
416 | struct tw5864_dev *dev = input->root; | ||
417 | unsigned long flags; | ||
418 | |||
419 | dev_dbg(&dev->pci->dev, "Disabling channel %d\n", input->nr); | ||
420 | |||
421 | spin_lock_irqsave(&dev->slock, flags); | ||
422 | input->enabled = 0; | ||
423 | spin_unlock_irqrestore(&dev->slock, flags); | ||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static int tw5864_start_streaming(struct vb2_queue *q, unsigned int count) | ||
428 | { | ||
429 | struct tw5864_input *input = vb2_get_drv_priv(q); | ||
430 | int ret; | ||
431 | |||
432 | ret = tw5864_enable_input(input); | ||
433 | if (!ret) | ||
434 | return 0; | ||
435 | |||
436 | while (!list_empty(&input->active)) { | ||
437 | struct tw5864_buf *buf = list_entry(input->active.next, | ||
438 | struct tw5864_buf, list); | ||
439 | |||
440 | list_del(&buf->list); | ||
441 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); | ||
442 | } | ||
443 | return ret; | ||
444 | } | ||
445 | |||
446 | static void tw5864_stop_streaming(struct vb2_queue *q) | ||
447 | { | ||
448 | unsigned long flags; | ||
449 | struct tw5864_input *input = vb2_get_drv_priv(q); | ||
450 | |||
451 | tw5864_disable_input(input); | ||
452 | |||
453 | spin_lock_irqsave(&input->slock, flags); | ||
454 | if (input->vb) { | ||
455 | vb2_buffer_done(&input->vb->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
456 | input->vb = NULL; | ||
457 | } | ||
458 | while (!list_empty(&input->active)) { | ||
459 | struct tw5864_buf *buf = list_entry(input->active.next, | ||
460 | struct tw5864_buf, list); | ||
461 | |||
462 | list_del(&buf->list); | ||
463 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
464 | } | ||
465 | spin_unlock_irqrestore(&input->slock, flags); | ||
466 | } | ||
467 | |||
468 | static const struct vb2_ops tw5864_video_qops = { | ||
469 | .queue_setup = tw5864_queue_setup, | ||
470 | .buf_queue = tw5864_buf_queue, | ||
471 | .start_streaming = tw5864_start_streaming, | ||
472 | .stop_streaming = tw5864_stop_streaming, | ||
473 | .wait_prepare = vb2_ops_wait_prepare, | ||
474 | .wait_finish = vb2_ops_wait_finish, | ||
475 | }; | ||
476 | |||
477 | static int tw5864_s_ctrl(struct v4l2_ctrl *ctrl) | ||
478 | { | ||
479 | struct tw5864_input *input = | ||
480 | container_of(ctrl->handler, struct tw5864_input, hdl); | ||
481 | struct tw5864_dev *dev = input->root; | ||
482 | unsigned long flags; | ||
483 | |||
484 | switch (ctrl->id) { | ||
485 | case V4L2_CID_BRIGHTNESS: | ||
486 | tw_indir_writeb(TW5864_INDIR_VIN_A_BRIGHT(input->nr), | ||
487 | (u8)ctrl->val); | ||
488 | break; | ||
489 | case V4L2_CID_HUE: | ||
490 | tw_indir_writeb(TW5864_INDIR_VIN_7_HUE(input->nr), | ||
491 | (u8)ctrl->val); | ||
492 | break; | ||
493 | case V4L2_CID_CONTRAST: | ||
494 | tw_indir_writeb(TW5864_INDIR_VIN_9_CNTRST(input->nr), | ||
495 | (u8)ctrl->val); | ||
496 | break; | ||
497 | case V4L2_CID_SATURATION: | ||
498 | tw_indir_writeb(TW5864_INDIR_VIN_B_SAT_U(input->nr), | ||
499 | (u8)ctrl->val); | ||
500 | tw_indir_writeb(TW5864_INDIR_VIN_C_SAT_V(input->nr), | ||
501 | (u8)ctrl->val); | ||
502 | break; | ||
503 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
504 | input->gop = ctrl->val; | ||
505 | return 0; | ||
506 | case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: | ||
507 | spin_lock_irqsave(&input->slock, flags); | ||
508 | input->qp = ctrl->val; | ||
509 | input->reg_dsp_qp = input->qp; | ||
510 | input->reg_dsp_ref_mvp_lambda = lambda_lookup_table[input->qp]; | ||
511 | input->reg_dsp_i4x4_weight = intra4x4_lambda3[input->qp]; | ||
512 | spin_unlock_irqrestore(&input->slock, flags); | ||
513 | return 0; | ||
514 | case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: | ||
515 | memset(input->md_threshold_grid_values, ctrl->val, | ||
516 | sizeof(input->md_threshold_grid_values)); | ||
517 | return 0; | ||
518 | case V4L2_CID_DETECT_MD_MODE: | ||
519 | return 0; | ||
520 | case V4L2_CID_DETECT_MD_THRESHOLD_GRID: | ||
521 | /* input->md_threshold_grid_ctrl->p_new.p_u16 contains data */ | ||
522 | memcpy(input->md_threshold_grid_values, | ||
523 | input->md_threshold_grid_ctrl->p_new.p_u16, | ||
524 | sizeof(input->md_threshold_grid_values)); | ||
525 | return 0; | ||
526 | } | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | static int tw5864_fmt_vid_cap(struct file *file, void *priv, | ||
531 | struct v4l2_format *f) | ||
532 | { | ||
533 | struct tw5864_input *input = video_drvdata(file); | ||
534 | |||
535 | f->fmt.pix.width = 720; | ||
536 | switch (input->std) { | ||
537 | default: | ||
538 | WARN_ON_ONCE(1); | ||
539 | case STD_NTSC: | ||
540 | f->fmt.pix.height = 480; | ||
541 | break; | ||
542 | case STD_PAL: | ||
543 | case STD_SECAM: | ||
544 | f->fmt.pix.height = 576; | ||
545 | break; | ||
546 | } | ||
547 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
548 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264; | ||
549 | f->fmt.pix.sizeimage = H264_VLC_BUF_SIZE; | ||
550 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | static int tw5864_enum_input(struct file *file, void *priv, | ||
555 | struct v4l2_input *i) | ||
556 | { | ||
557 | struct tw5864_input *input = video_drvdata(file); | ||
558 | struct tw5864_dev *dev = input->root; | ||
559 | |||
560 | u8 indir_0x000 = tw_indir_readb(TW5864_INDIR_VIN_0(input->nr)); | ||
561 | u8 indir_0x00d = tw_indir_readb(TW5864_INDIR_VIN_D(input->nr)); | ||
562 | u8 v1 = indir_0x000; | ||
563 | u8 v2 = indir_0x00d; | ||
564 | |||
565 | if (i->index) | ||
566 | return -EINVAL; | ||
567 | |||
568 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
569 | snprintf(i->name, sizeof(i->name), "Encoder %d", input->nr); | ||
570 | i->std = TW5864_NORMS; | ||
571 | if (v1 & (1 << 7)) | ||
572 | i->status |= V4L2_IN_ST_NO_SYNC; | ||
573 | if (!(v1 & (1 << 6))) | ||
574 | i->status |= V4L2_IN_ST_NO_H_LOCK; | ||
575 | if (v1 & (1 << 2)) | ||
576 | i->status |= V4L2_IN_ST_NO_SIGNAL; | ||
577 | if (v1 & (1 << 1)) | ||
578 | i->status |= V4L2_IN_ST_NO_COLOR; | ||
579 | if (v2 & (1 << 2)) | ||
580 | i->status |= V4L2_IN_ST_MACROVISION; | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static int tw5864_g_input(struct file *file, void *priv, unsigned int *i) | ||
586 | { | ||
587 | *i = 0; | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | static int tw5864_s_input(struct file *file, void *priv, unsigned int i) | ||
592 | { | ||
593 | if (i) | ||
594 | return -EINVAL; | ||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | static int tw5864_querycap(struct file *file, void *priv, | ||
599 | struct v4l2_capability *cap) | ||
600 | { | ||
601 | struct tw5864_input *input = video_drvdata(file); | ||
602 | |||
603 | strcpy(cap->driver, "tw5864"); | ||
604 | snprintf(cap->card, sizeof(cap->card), "TW5864 Encoder %d", | ||
605 | input->nr); | ||
606 | sprintf(cap->bus_info, "PCI:%s", pci_name(input->root->pci)); | ||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | static int tw5864_querystd(struct file *file, void *priv, v4l2_std_id *std) | ||
611 | { | ||
612 | struct tw5864_input *input = video_drvdata(file); | ||
613 | enum tw5864_vid_std tw_std; | ||
614 | int ret; | ||
615 | |||
616 | ret = tw5864_input_std_get(input, &tw_std); | ||
617 | if (ret) | ||
618 | return ret; | ||
619 | *std = tw5864_get_v4l2_std(tw_std); | ||
620 | |||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | static int tw5864_g_std(struct file *file, void *priv, v4l2_std_id *std) | ||
625 | { | ||
626 | struct tw5864_input *input = video_drvdata(file); | ||
627 | |||
628 | *std = input->v4l2_std; | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | static int tw5864_s_std(struct file *file, void *priv, v4l2_std_id std) | ||
633 | { | ||
634 | struct tw5864_input *input = video_drvdata(file); | ||
635 | struct tw5864_dev *dev = input->root; | ||
636 | |||
637 | input->v4l2_std = std; | ||
638 | input->std = tw5864_from_v4l2_std(std); | ||
639 | tw_indir_writeb(TW5864_INDIR_VIN_E(input->nr), input->std); | ||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | static int tw5864_enum_fmt_vid_cap(struct file *file, void *priv, | ||
644 | struct v4l2_fmtdesc *f) | ||
645 | { | ||
646 | if (f->index) | ||
647 | return -EINVAL; | ||
648 | |||
649 | f->pixelformat = V4L2_PIX_FMT_H264; | ||
650 | |||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | static int tw5864_subscribe_event(struct v4l2_fh *fh, | ||
655 | const struct v4l2_event_subscription *sub) | ||
656 | { | ||
657 | switch (sub->type) { | ||
658 | case V4L2_EVENT_CTRL: | ||
659 | return v4l2_ctrl_subscribe_event(fh, sub); | ||
660 | case V4L2_EVENT_MOTION_DET: | ||
661 | /* | ||
662 | * Allow for up to 30 events (1 second for NTSC) to be stored. | ||
663 | */ | ||
664 | return v4l2_event_subscribe(fh, sub, 30, NULL); | ||
665 | } | ||
666 | return -EINVAL; | ||
667 | } | ||
668 | |||
669 | static void tw5864_frame_interval_set(struct tw5864_input *input) | ||
670 | { | ||
671 | /* | ||
672 | * This register value seems to follow such approach: In each second | ||
673 | * interval, when processing Nth frame, it checks Nth bit of register | ||
674 | * value and, if the bit is 1, it processes the frame, otherwise the | ||
675 | * frame is discarded. | ||
676 | * So unary representation would work, but more or less equal gaps | ||
677 | * between the frames should be preserved. | ||
678 | * | ||
679 | * For 1 FPS - 0x00000001 | ||
680 | * 00000000 00000000 00000000 00000001 | ||
681 | * | ||
682 | * For max FPS - set all 25/30 lower bits: | ||
683 | * 00111111 11111111 11111111 11111111 (NTSC) | ||
684 | * 00000001 11111111 11111111 11111111 (PAL) | ||
685 | * | ||
686 | * For half of max FPS - use such pattern: | ||
687 | * 00010101 01010101 01010101 01010101 (NTSC) | ||
688 | * 00000001 01010101 01010101 01010101 (PAL) | ||
689 | * | ||
690 | * Et cetera. | ||
691 | * | ||
692 | * The value supplied to hardware is capped by mask of 25/30 lower bits. | ||
693 | */ | ||
694 | struct tw5864_dev *dev = input->root; | ||
695 | u32 unary_framerate = 0; | ||
696 | int shift = 0; | ||
697 | int std_max_fps = input->std == STD_NTSC ? 30 : 25; | ||
698 | |||
699 | for (shift = 0; shift < std_max_fps; shift += input->frame_interval) | ||
700 | unary_framerate |= 0x00000001 << shift; | ||
701 | |||
702 | tw_writel(TW5864_H264EN_RATE_CNTL_LO_WORD(input->nr, 0), | ||
703 | unary_framerate >> 16); | ||
704 | tw_writel(TW5864_H264EN_RATE_CNTL_HI_WORD(input->nr, 0), | ||
705 | unary_framerate & 0xffff); | ||
706 | } | ||
707 | |||
708 | static int tw5864_frameinterval_get(struct tw5864_input *input, | ||
709 | struct v4l2_fract *frameinterval) | ||
710 | { | ||
711 | switch (input->std) { | ||
712 | case STD_NTSC: | ||
713 | frameinterval->numerator = 1001; | ||
714 | frameinterval->denominator = 30000; | ||
715 | break; | ||
716 | case STD_PAL: | ||
717 | case STD_SECAM: | ||
718 | frameinterval->numerator = 1; | ||
719 | frameinterval->denominator = 25; | ||
720 | break; | ||
721 | default: | ||
722 | WARN(1, "tw5864_frameinterval_get requested for unknown std %d\n", | ||
723 | input->std); | ||
724 | return -EINVAL; | ||
725 | } | ||
726 | |||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | static int tw5864_enum_framesizes(struct file *file, void *priv, | ||
731 | struct v4l2_frmsizeenum *fsize) | ||
732 | { | ||
733 | struct tw5864_input *input = video_drvdata(file); | ||
734 | |||
735 | if (fsize->index > 0) | ||
736 | return -EINVAL; | ||
737 | if (fsize->pixel_format != V4L2_PIX_FMT_H264) | ||
738 | return -EINVAL; | ||
739 | |||
740 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
741 | fsize->discrete.width = 720; | ||
742 | fsize->discrete.height = input->std == STD_NTSC ? 480 : 576; | ||
743 | |||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | static int tw5864_enum_frameintervals(struct file *file, void *priv, | ||
748 | struct v4l2_frmivalenum *fintv) | ||
749 | { | ||
750 | struct tw5864_input *input = video_drvdata(file); | ||
751 | struct v4l2_fract frameinterval; | ||
752 | int std_max_fps = input->std == STD_NTSC ? 30 : 25; | ||
753 | struct v4l2_frmsizeenum fsize = { .index = fintv->index, | ||
754 | .pixel_format = fintv->pixel_format }; | ||
755 | int ret; | ||
756 | |||
757 | ret = tw5864_enum_framesizes(file, priv, &fsize); | ||
758 | if (ret) | ||
759 | return ret; | ||
760 | |||
761 | if (fintv->width != fsize.discrete.width || | ||
762 | fintv->height != fsize.discrete.height) | ||
763 | return -EINVAL; | ||
764 | |||
765 | fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE; | ||
766 | |||
767 | ret = tw5864_frameinterval_get(input, &frameinterval); | ||
768 | fintv->stepwise.step = frameinterval; | ||
769 | fintv->stepwise.min = frameinterval; | ||
770 | fintv->stepwise.max = frameinterval; | ||
771 | fintv->stepwise.max.numerator *= std_max_fps; | ||
772 | |||
773 | return ret; | ||
774 | } | ||
775 | |||
776 | static int tw5864_g_parm(struct file *file, void *priv, | ||
777 | struct v4l2_streamparm *sp) | ||
778 | { | ||
779 | struct tw5864_input *input = video_drvdata(file); | ||
780 | struct v4l2_captureparm *cp = &sp->parm.capture; | ||
781 | int ret; | ||
782 | |||
783 | cp->capability = V4L2_CAP_TIMEPERFRAME; | ||
784 | |||
785 | ret = tw5864_frameinterval_get(input, &cp->timeperframe); | ||
786 | cp->timeperframe.numerator *= input->frame_interval; | ||
787 | cp->capturemode = 0; | ||
788 | cp->readbuffers = 2; | ||
789 | |||
790 | return ret; | ||
791 | } | ||
792 | |||
793 | static int tw5864_s_parm(struct file *file, void *priv, | ||
794 | struct v4l2_streamparm *sp) | ||
795 | { | ||
796 | struct tw5864_input *input = video_drvdata(file); | ||
797 | struct v4l2_fract *t = &sp->parm.capture.timeperframe; | ||
798 | struct v4l2_fract time_base; | ||
799 | int ret; | ||
800 | |||
801 | ret = tw5864_frameinterval_get(input, &time_base); | ||
802 | if (ret) | ||
803 | return ret; | ||
804 | |||
805 | if (!t->numerator || !t->denominator) { | ||
806 | t->numerator = time_base.numerator * input->frame_interval; | ||
807 | t->denominator = time_base.denominator; | ||
808 | } else if (t->denominator != time_base.denominator) { | ||
809 | t->numerator = t->numerator * time_base.denominator / | ||
810 | t->denominator; | ||
811 | t->denominator = time_base.denominator; | ||
812 | } | ||
813 | |||
814 | input->frame_interval = t->numerator / time_base.numerator; | ||
815 | if (input->frame_interval < 1) | ||
816 | input->frame_interval = 1; | ||
817 | tw5864_frame_interval_set(input); | ||
818 | return tw5864_g_parm(file, priv, sp); | ||
819 | } | ||
820 | |||
821 | static const struct v4l2_ctrl_ops tw5864_ctrl_ops = { | ||
822 | .s_ctrl = tw5864_s_ctrl, | ||
823 | }; | ||
824 | |||
825 | static const struct v4l2_file_operations video_fops = { | ||
826 | .owner = THIS_MODULE, | ||
827 | .open = v4l2_fh_open, | ||
828 | .release = vb2_fop_release, | ||
829 | .read = vb2_fop_read, | ||
830 | .poll = vb2_fop_poll, | ||
831 | .mmap = vb2_fop_mmap, | ||
832 | .unlocked_ioctl = video_ioctl2, | ||
833 | }; | ||
834 | |||
835 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
836 | |||
837 | #define INDIR_SPACE_MAP_SHIFT 0x100000 | ||
838 | |||
839 | static int tw5864_g_reg(struct file *file, void *fh, | ||
840 | struct v4l2_dbg_register *reg) | ||
841 | { | ||
842 | struct tw5864_input *input = video_drvdata(file); | ||
843 | struct tw5864_dev *dev = input->root; | ||
844 | |||
845 | if (reg->reg < INDIR_SPACE_MAP_SHIFT) { | ||
846 | if (reg->reg > 0x87fff) | ||
847 | return -EINVAL; | ||
848 | reg->size = 4; | ||
849 | reg->val = tw_readl(reg->reg); | ||
850 | } else { | ||
851 | __u64 indir_addr = reg->reg - INDIR_SPACE_MAP_SHIFT; | ||
852 | |||
853 | if (indir_addr > 0xefe) | ||
854 | return -EINVAL; | ||
855 | reg->size = 1; | ||
856 | reg->val = tw_indir_readb(reg->reg); | ||
857 | } | ||
858 | return 0; | ||
859 | } | ||
860 | |||
861 | static int tw5864_s_reg(struct file *file, void *fh, | ||
862 | const struct v4l2_dbg_register *reg) | ||
863 | { | ||
864 | struct tw5864_input *input = video_drvdata(file); | ||
865 | struct tw5864_dev *dev = input->root; | ||
866 | |||
867 | if (reg->reg < INDIR_SPACE_MAP_SHIFT) { | ||
868 | if (reg->reg > 0x87fff) | ||
869 | return -EINVAL; | ||
870 | tw_writel(reg->reg, reg->val); | ||
871 | } else { | ||
872 | __u64 indir_addr = reg->reg - INDIR_SPACE_MAP_SHIFT; | ||
873 | |||
874 | if (indir_addr > 0xefe) | ||
875 | return -EINVAL; | ||
876 | tw_indir_writeb(reg->reg, reg->val); | ||
877 | } | ||
878 | return 0; | ||
879 | } | ||
880 | #endif | ||
881 | |||
882 | static const struct v4l2_ioctl_ops video_ioctl_ops = { | ||
883 | .vidioc_querycap = tw5864_querycap, | ||
884 | .vidioc_enum_fmt_vid_cap = tw5864_enum_fmt_vid_cap, | ||
885 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
886 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
887 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
888 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
889 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
890 | .vidioc_expbuf = vb2_ioctl_expbuf, | ||
891 | .vidioc_querystd = tw5864_querystd, | ||
892 | .vidioc_s_std = tw5864_s_std, | ||
893 | .vidioc_g_std = tw5864_g_std, | ||
894 | .vidioc_enum_input = tw5864_enum_input, | ||
895 | .vidioc_g_input = tw5864_g_input, | ||
896 | .vidioc_s_input = tw5864_s_input, | ||
897 | .vidioc_streamon = vb2_ioctl_streamon, | ||
898 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
899 | .vidioc_try_fmt_vid_cap = tw5864_fmt_vid_cap, | ||
900 | .vidioc_s_fmt_vid_cap = tw5864_fmt_vid_cap, | ||
901 | .vidioc_g_fmt_vid_cap = tw5864_fmt_vid_cap, | ||
902 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
903 | .vidioc_subscribe_event = tw5864_subscribe_event, | ||
904 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
905 | .vidioc_enum_framesizes = tw5864_enum_framesizes, | ||
906 | .vidioc_enum_frameintervals = tw5864_enum_frameintervals, | ||
907 | .vidioc_s_parm = tw5864_s_parm, | ||
908 | .vidioc_g_parm = tw5864_g_parm, | ||
909 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
910 | .vidioc_g_register = tw5864_g_reg, | ||
911 | .vidioc_s_register = tw5864_s_reg, | ||
912 | #endif | ||
913 | }; | ||
914 | |||
915 | static const struct video_device tw5864_video_template = { | ||
916 | .name = "tw5864_video", | ||
917 | .fops = &video_fops, | ||
918 | .ioctl_ops = &video_ioctl_ops, | ||
919 | .release = video_device_release_empty, | ||
920 | .tvnorms = TW5864_NORMS, | ||
921 | .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | | ||
922 | V4L2_CAP_STREAMING, | ||
923 | }; | ||
924 | |||
925 | /* Motion Detection Threshold matrix */ | ||
926 | static const struct v4l2_ctrl_config tw5864_md_thresholds = { | ||
927 | .ops = &tw5864_ctrl_ops, | ||
928 | .id = V4L2_CID_DETECT_MD_THRESHOLD_GRID, | ||
929 | .dims = {MD_CELLS_HOR, MD_CELLS_VERT}, | ||
930 | .def = 14, | ||
931 | /* See tw5864_md_metric_from_mvd() */ | ||
932 | .max = 2 * 0x0f, | ||
933 | .step = 1, | ||
934 | }; | ||
935 | |||
936 | static int tw5864_video_input_init(struct tw5864_input *dev, int video_nr); | ||
937 | static void tw5864_video_input_fini(struct tw5864_input *dev); | ||
938 | static void tw5864_encoder_tables_upload(struct tw5864_dev *dev); | ||
939 | |||
940 | int tw5864_video_init(struct tw5864_dev *dev, int *video_nr) | ||
941 | { | ||
942 | int i; | ||
943 | int ret; | ||
944 | unsigned long flags; | ||
945 | int last_dma_allocated = -1; | ||
946 | int last_input_nr_registered = -1; | ||
947 | |||
948 | for (i = 0; i < H264_BUF_CNT; i++) { | ||
949 | struct tw5864_h264_frame *frame = &dev->h264_buf[i]; | ||
950 | |||
951 | frame->vlc.addr = dma_alloc_coherent(&dev->pci->dev, | ||
952 | H264_VLC_BUF_SIZE, | ||
953 | &frame->vlc.dma_addr, | ||
954 | GFP_KERNEL | GFP_DMA32); | ||
955 | if (!frame->vlc.addr) { | ||
956 | dev_err(&dev->pci->dev, "dma alloc fail\n"); | ||
957 | ret = -ENOMEM; | ||
958 | goto free_dma; | ||
959 | } | ||
960 | frame->mv.addr = dma_alloc_coherent(&dev->pci->dev, | ||
961 | H264_MV_BUF_SIZE, | ||
962 | &frame->mv.dma_addr, | ||
963 | GFP_KERNEL | GFP_DMA32); | ||
964 | if (!frame->mv.addr) { | ||
965 | dev_err(&dev->pci->dev, "dma alloc fail\n"); | ||
966 | ret = -ENOMEM; | ||
967 | dma_free_coherent(&dev->pci->dev, H264_VLC_BUF_SIZE, | ||
968 | frame->vlc.addr, frame->vlc.dma_addr); | ||
969 | goto free_dma; | ||
970 | } | ||
971 | last_dma_allocated = i; | ||
972 | } | ||
973 | |||
974 | tw5864_encoder_tables_upload(dev); | ||
975 | |||
976 | /* Picture is distorted without this block */ | ||
977 | /* use falling edge to sample 54M to 108M */ | ||
978 | tw_indir_writeb(TW5864_INDIR_VD_108_POL, TW5864_INDIR_VD_108_POL_BOTH); | ||
979 | tw_indir_writeb(TW5864_INDIR_CLK0_SEL, 0x00); | ||
980 | |||
981 | tw_indir_writeb(TW5864_INDIR_DDRA_DLL_DQS_SEL0, 0x02); | ||
982 | tw_indir_writeb(TW5864_INDIR_DDRA_DLL_DQS_SEL1, 0x02); | ||
983 | tw_indir_writeb(TW5864_INDIR_DDRA_DLL_CLK90_SEL, 0x02); | ||
984 | tw_indir_writeb(TW5864_INDIR_DDRB_DLL_DQS_SEL0, 0x02); | ||
985 | tw_indir_writeb(TW5864_INDIR_DDRB_DLL_DQS_SEL1, 0x02); | ||
986 | tw_indir_writeb(TW5864_INDIR_DDRB_DLL_CLK90_SEL, 0x02); | ||
987 | |||
988 | /* video input reset */ | ||
989 | tw_indir_writeb(TW5864_INDIR_RESET, 0); | ||
990 | tw_indir_writeb(TW5864_INDIR_RESET, TW5864_INDIR_RESET_VD | | ||
991 | TW5864_INDIR_RESET_DLL | TW5864_INDIR_RESET_MUX_CORE); | ||
992 | msleep(20); | ||
993 | |||
994 | /* | ||
995 | * Select Part A mode for all channels. | ||
996 | * tw_setl instead of tw_clearl for Part B mode. | ||
997 | * | ||
998 | * I guess "Part B" is primarily for downscaled version of same channel | ||
999 | * which goes in Part A of same bus | ||
1000 | */ | ||
1001 | tw_writel(TW5864_FULL_HALF_MODE_SEL, 0); | ||
1002 | |||
1003 | tw_indir_writeb(TW5864_INDIR_PV_VD_CK_POL, | ||
1004 | TW5864_INDIR_PV_VD_CK_POL_VD(0) | | ||
1005 | TW5864_INDIR_PV_VD_CK_POL_VD(1) | | ||
1006 | TW5864_INDIR_PV_VD_CK_POL_VD(2) | | ||
1007 | TW5864_INDIR_PV_VD_CK_POL_VD(3)); | ||
1008 | |||
1009 | spin_lock_irqsave(&dev->slock, flags); | ||
1010 | dev->encoder_busy = 0; | ||
1011 | dev->h264_buf_r_index = 0; | ||
1012 | dev->h264_buf_w_index = 0; | ||
1013 | tw_writel(TW5864_VLC_STREAM_BASE_ADDR, | ||
1014 | dev->h264_buf[dev->h264_buf_w_index].vlc.dma_addr); | ||
1015 | tw_writel(TW5864_MV_STREAM_BASE_ADDR, | ||
1016 | dev->h264_buf[dev->h264_buf_w_index].mv.dma_addr); | ||
1017 | spin_unlock_irqrestore(&dev->slock, flags); | ||
1018 | |||
1019 | tw_writel(TW5864_SEN_EN_CH, 0x000f); | ||
1020 | tw_writel(TW5864_H264EN_CH_EN, 0x000f); | ||
1021 | |||
1022 | tw_writel(TW5864_H264EN_BUS0_MAP, 0x00000000); | ||
1023 | tw_writel(TW5864_H264EN_BUS1_MAP, 0x00001111); | ||
1024 | tw_writel(TW5864_H264EN_BUS2_MAP, 0x00002222); | ||
1025 | tw_writel(TW5864_H264EN_BUS3_MAP, 0x00003333); | ||
1026 | |||
1027 | /* | ||
1028 | * Quote from Intersil (manufacturer): | ||
1029 | * 0x0038 is managed by HW, and by default it won't pass the pointer set | ||
1030 | * at 0x0010. So if you don't do encoding, 0x0038 should stay at '3' | ||
1031 | * (with 4 frames in buffer). If you encode one frame and then move | ||
1032 | * 0x0010 to '1' for example, HW will take one more frame and set it to | ||
1033 | * buffer #0, and then you should see 0x0038 is set to '0'. There is | ||
1034 | * only one HW encoder engine, so 4 channels cannot get encoded | ||
1035 | * simultaneously. But each channel does have its own buffer (for | ||
1036 | * original frames and reconstructed frames). So there is no problem to | ||
1037 | * manage encoding for 4 channels at same time and no need to force | ||
1038 | * I-frames in switching channels. | ||
1039 | * End of quote. | ||
1040 | * | ||
1041 | * If we set 0x0010 (TW5864_ENC_BUF_PTR_REC1) to 0 (for any channel), we | ||
1042 | * have no "rolling" (until we change this value). | ||
1043 | * If we set 0x0010 (TW5864_ENC_BUF_PTR_REC1) to 0x3, it starts to roll | ||
1044 | * continuously together with 0x0038. | ||
1045 | */ | ||
1046 | tw_writel(TW5864_ENC_BUF_PTR_REC1, 0x00ff); | ||
1047 | tw_writel(TW5864_PCI_INTTM_SCALE, 0); | ||
1048 | |||
1049 | tw_writel(TW5864_INTERLACING, TW5864_DI_EN); | ||
1050 | tw_writel(TW5864_MASTER_ENB_REG, TW5864_PCI_VLC_INTR_ENB); | ||
1051 | tw_writel(TW5864_PCI_INTR_CTL, | ||
1052 | TW5864_TIMER_INTR_ENB | TW5864_PCI_MAST_ENB | | ||
1053 | TW5864_MVD_VLC_MAST_ENB); | ||
1054 | |||
1055 | dev->irqmask |= TW5864_INTR_VLC_DONE | TW5864_INTR_TIMER; | ||
1056 | tw5864_irqmask_apply(dev); | ||
1057 | |||
1058 | tasklet_init(&dev->tasklet, tw5864_handle_frame_task, | ||
1059 | (unsigned long)dev); | ||
1060 | |||
1061 | for (i = 0; i < TW5864_INPUTS; i++) { | ||
1062 | dev->inputs[i].root = dev; | ||
1063 | dev->inputs[i].nr = i; | ||
1064 | ret = tw5864_video_input_init(&dev->inputs[i], video_nr[i]); | ||
1065 | if (ret) | ||
1066 | goto fini_video_inputs; | ||
1067 | last_input_nr_registered = i; | ||
1068 | } | ||
1069 | |||
1070 | return 0; | ||
1071 | |||
1072 | fini_video_inputs: | ||
1073 | for (i = last_input_nr_registered; i >= 0; i--) | ||
1074 | tw5864_video_input_fini(&dev->inputs[i]); | ||
1075 | |||
1076 | tasklet_kill(&dev->tasklet); | ||
1077 | |||
1078 | free_dma: | ||
1079 | for (i = last_dma_allocated; i >= 0; i--) { | ||
1080 | dma_free_coherent(&dev->pci->dev, H264_VLC_BUF_SIZE, | ||
1081 | dev->h264_buf[i].vlc.addr, | ||
1082 | dev->h264_buf[i].vlc.dma_addr); | ||
1083 | dma_free_coherent(&dev->pci->dev, H264_MV_BUF_SIZE, | ||
1084 | dev->h264_buf[i].mv.addr, | ||
1085 | dev->h264_buf[i].mv.dma_addr); | ||
1086 | } | ||
1087 | |||
1088 | return ret; | ||
1089 | } | ||
1090 | |||
1091 | static int tw5864_video_input_init(struct tw5864_input *input, int video_nr) | ||
1092 | { | ||
1093 | struct tw5864_dev *dev = input->root; | ||
1094 | int ret; | ||
1095 | struct v4l2_ctrl_handler *hdl = &input->hdl; | ||
1096 | |||
1097 | mutex_init(&input->lock); | ||
1098 | spin_lock_init(&input->slock); | ||
1099 | |||
1100 | /* setup video buffers queue */ | ||
1101 | INIT_LIST_HEAD(&input->active); | ||
1102 | input->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1103 | input->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
1104 | input->vidq.io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; | ||
1105 | input->vidq.ops = &tw5864_video_qops; | ||
1106 | input->vidq.mem_ops = &vb2_dma_contig_memops; | ||
1107 | input->vidq.drv_priv = input; | ||
1108 | input->vidq.gfp_flags = 0; | ||
1109 | input->vidq.buf_struct_size = sizeof(struct tw5864_buf); | ||
1110 | input->vidq.lock = &input->lock; | ||
1111 | input->vidq.min_buffers_needed = 2; | ||
1112 | input->vidq.dev = &input->root->pci->dev; | ||
1113 | ret = vb2_queue_init(&input->vidq); | ||
1114 | if (ret) | ||
1115 | goto free_mutex; | ||
1116 | |||
1117 | input->vdev = tw5864_video_template; | ||
1118 | input->vdev.v4l2_dev = &input->root->v4l2_dev; | ||
1119 | input->vdev.lock = &input->lock; | ||
1120 | input->vdev.queue = &input->vidq; | ||
1121 | video_set_drvdata(&input->vdev, input); | ||
1122 | |||
1123 | /* Initialize the device control structures */ | ||
1124 | v4l2_ctrl_handler_init(hdl, 6); | ||
1125 | v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, | ||
1126 | V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); | ||
1127 | v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, | ||
1128 | V4L2_CID_CONTRAST, 0, 255, 1, 100); | ||
1129 | v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, | ||
1130 | V4L2_CID_SATURATION, 0, 255, 1, 128); | ||
1131 | v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, V4L2_CID_HUE, -128, 127, 1, 0); | ||
1132 | v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, | ||
1133 | 1, MAX_GOP_SIZE, 1, GOP_SIZE); | ||
1134 | v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, | ||
1135 | V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 28, 51, 1, QP_VALUE); | ||
1136 | v4l2_ctrl_new_std_menu(hdl, &tw5864_ctrl_ops, | ||
1137 | V4L2_CID_DETECT_MD_MODE, | ||
1138 | V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 0, | ||
1139 | V4L2_DETECT_MD_MODE_DISABLED); | ||
1140 | v4l2_ctrl_new_std(hdl, &tw5864_ctrl_ops, | ||
1141 | V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, | ||
1142 | tw5864_md_thresholds.min, tw5864_md_thresholds.max, | ||
1143 | tw5864_md_thresholds.step, tw5864_md_thresholds.def); | ||
1144 | input->md_threshold_grid_ctrl = | ||
1145 | v4l2_ctrl_new_custom(hdl, &tw5864_md_thresholds, NULL); | ||
1146 | if (hdl->error) { | ||
1147 | ret = hdl->error; | ||
1148 | goto free_v4l2_hdl; | ||
1149 | } | ||
1150 | input->vdev.ctrl_handler = hdl; | ||
1151 | v4l2_ctrl_handler_setup(hdl); | ||
1152 | |||
1153 | input->qp = QP_VALUE; | ||
1154 | input->gop = GOP_SIZE; | ||
1155 | input->frame_interval = 1; | ||
1156 | |||
1157 | ret = video_register_device(&input->vdev, VFL_TYPE_GRABBER, video_nr); | ||
1158 | if (ret) | ||
1159 | goto free_v4l2_hdl; | ||
1160 | |||
1161 | dev_info(&input->root->pci->dev, "Registered video device %s\n", | ||
1162 | video_device_node_name(&input->vdev)); | ||
1163 | |||
1164 | /* | ||
1165 | * Set default video standard. Doesn't matter which, the detected value | ||
1166 | * will be found out by VIDIOC_QUERYSTD handler. | ||
1167 | */ | ||
1168 | input->v4l2_std = V4L2_STD_NTSC_M; | ||
1169 | input->std = STD_NTSC; | ||
1170 | |||
1171 | tw_indir_writeb(TW5864_INDIR_VIN_E(video_nr), 0x07); | ||
1172 | /* to initiate auto format recognition */ | ||
1173 | tw_indir_writeb(TW5864_INDIR_VIN_F(video_nr), 0xff); | ||
1174 | |||
1175 | return 0; | ||
1176 | |||
1177 | free_v4l2_hdl: | ||
1178 | v4l2_ctrl_handler_free(hdl); | ||
1179 | vb2_queue_release(&input->vidq); | ||
1180 | free_mutex: | ||
1181 | mutex_destroy(&input->lock); | ||
1182 | |||
1183 | return ret; | ||
1184 | } | ||
1185 | |||
1186 | static void tw5864_video_input_fini(struct tw5864_input *dev) | ||
1187 | { | ||
1188 | video_unregister_device(&dev->vdev); | ||
1189 | v4l2_ctrl_handler_free(&dev->hdl); | ||
1190 | vb2_queue_release(&dev->vidq); | ||
1191 | } | ||
1192 | |||
1193 | void tw5864_video_fini(struct tw5864_dev *dev) | ||
1194 | { | ||
1195 | int i; | ||
1196 | |||
1197 | tasklet_kill(&dev->tasklet); | ||
1198 | |||
1199 | for (i = 0; i < TW5864_INPUTS; i++) | ||
1200 | tw5864_video_input_fini(&dev->inputs[i]); | ||
1201 | |||
1202 | for (i = 0; i < H264_BUF_CNT; i++) { | ||
1203 | dma_free_coherent(&dev->pci->dev, H264_VLC_BUF_SIZE, | ||
1204 | dev->h264_buf[i].vlc.addr, | ||
1205 | dev->h264_buf[i].vlc.dma_addr); | ||
1206 | dma_free_coherent(&dev->pci->dev, H264_MV_BUF_SIZE, | ||
1207 | dev->h264_buf[i].mv.addr, | ||
1208 | dev->h264_buf[i].mv.dma_addr); | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1212 | void tw5864_prepare_frame_headers(struct tw5864_input *input) | ||
1213 | { | ||
1214 | struct tw5864_buf *vb = input->vb; | ||
1215 | u8 *dst; | ||
1216 | size_t dst_space; | ||
1217 | unsigned long flags; | ||
1218 | |||
1219 | if (!vb) { | ||
1220 | spin_lock_irqsave(&input->slock, flags); | ||
1221 | if (list_empty(&input->active)) { | ||
1222 | spin_unlock_irqrestore(&input->slock, flags); | ||
1223 | input->vb = NULL; | ||
1224 | return; | ||
1225 | } | ||
1226 | vb = list_first_entry(&input->active, struct tw5864_buf, list); | ||
1227 | list_del(&vb->list); | ||
1228 | spin_unlock_irqrestore(&input->slock, flags); | ||
1229 | } | ||
1230 | |||
1231 | dst = vb2_plane_vaddr(&vb->vb.vb2_buf, 0); | ||
1232 | dst_space = vb2_plane_size(&vb->vb.vb2_buf, 0); | ||
1233 | |||
1234 | /* | ||
1235 | * Low-level bitstream writing functions don't have a fine way to say | ||
1236 | * correctly that supplied buffer is too small. So we just check there | ||
1237 | * and warn, and don't care at lower level. | ||
1238 | * Currently all headers take below 32 bytes. | ||
1239 | * The buffer is supposed to have plenty of free space at this point, | ||
1240 | * anyway. | ||
1241 | */ | ||
1242 | if (WARN_ON_ONCE(dst_space < 128)) | ||
1243 | return; | ||
1244 | |||
1245 | /* | ||
1246 | * Generate H264 headers: | ||
1247 | * If this is first frame, put SPS and PPS | ||
1248 | */ | ||
1249 | if (input->frame_gop_seqno == 0) | ||
1250 | tw5864_h264_put_stream_header(&dst, &dst_space, input->qp, | ||
1251 | input->width, input->height); | ||
1252 | |||
1253 | /* Put slice header */ | ||
1254 | tw5864_h264_put_slice_header(&dst, &dst_space, input->h264_idr_pic_id, | ||
1255 | input->frame_gop_seqno, | ||
1256 | &input->tail_nb_bits, &input->tail); | ||
1257 | input->vb = vb; | ||
1258 | input->buf_cur_ptr = dst; | ||
1259 | input->buf_cur_space_left = dst_space; | ||
1260 | } | ||
1261 | |||
1262 | /* | ||
1263 | * Returns heuristic motion detection metric value from known components of | ||
1264 | * hardware-provided Motion Vector Data. | ||
1265 | */ | ||
1266 | static unsigned int tw5864_md_metric_from_mvd(u32 mvd) | ||
1267 | { | ||
1268 | /* | ||
1269 | * Format of motion vector data exposed by tw5864, according to | ||
1270 | * manufacturer: | ||
1271 | * mv_x 10 bits | ||
1272 | * mv_y 10 bits | ||
1273 | * non_zero_members 8 bits | ||
1274 | * mb_type 3 bits | ||
1275 | * reserved 1 bit | ||
1276 | * | ||
1277 | * non_zero_members: number of non-zero residuals in each macro block | ||
1278 | * after quantization | ||
1279 | * | ||
1280 | * unsigned int reserved = mvd >> 31; | ||
1281 | * unsigned int mb_type = (mvd >> 28) & 0x7; | ||
1282 | * unsigned int non_zero_members = (mvd >> 20) & 0xff; | ||
1283 | */ | ||
1284 | unsigned int mv_y = (mvd >> 10) & 0x3ff; | ||
1285 | unsigned int mv_x = mvd & 0x3ff; | ||
1286 | |||
1287 | /* heuristic: */ | ||
1288 | mv_x &= 0x0f; | ||
1289 | mv_y &= 0x0f; | ||
1290 | |||
1291 | return mv_y + mv_x; | ||
1292 | } | ||
1293 | |||
1294 | static int tw5864_is_motion_triggered(struct tw5864_h264_frame *frame) | ||
1295 | { | ||
1296 | struct tw5864_input *input = frame->input; | ||
1297 | u32 *mv = (u32 *)frame->mv.addr; | ||
1298 | int i; | ||
1299 | int detected = 0; | ||
1300 | |||
1301 | for (i = 0; i < MD_CELLS; i++) { | ||
1302 | const u16 thresh = input->md_threshold_grid_values[i]; | ||
1303 | const unsigned int metric = tw5864_md_metric_from_mvd(mv[i]); | ||
1304 | |||
1305 | if (metric > thresh) | ||
1306 | detected = 1; | ||
1307 | |||
1308 | if (detected) | ||
1309 | break; | ||
1310 | } | ||
1311 | return detected; | ||
1312 | } | ||
1313 | |||
1314 | static void tw5864_handle_frame_task(unsigned long data) | ||
1315 | { | ||
1316 | struct tw5864_dev *dev = (struct tw5864_dev *)data; | ||
1317 | unsigned long flags; | ||
1318 | int batch_size = H264_BUF_CNT; | ||
1319 | |||
1320 | spin_lock_irqsave(&dev->slock, flags); | ||
1321 | while (dev->h264_buf_r_index != dev->h264_buf_w_index && batch_size--) { | ||
1322 | struct tw5864_h264_frame *frame = | ||
1323 | &dev->h264_buf[dev->h264_buf_r_index]; | ||
1324 | |||
1325 | spin_unlock_irqrestore(&dev->slock, flags); | ||
1326 | dma_sync_single_for_cpu(&dev->pci->dev, frame->vlc.dma_addr, | ||
1327 | H264_VLC_BUF_SIZE, DMA_FROM_DEVICE); | ||
1328 | dma_sync_single_for_cpu(&dev->pci->dev, frame->mv.dma_addr, | ||
1329 | H264_MV_BUF_SIZE, DMA_FROM_DEVICE); | ||
1330 | tw5864_handle_frame(frame); | ||
1331 | dma_sync_single_for_device(&dev->pci->dev, frame->vlc.dma_addr, | ||
1332 | H264_VLC_BUF_SIZE, DMA_FROM_DEVICE); | ||
1333 | dma_sync_single_for_device(&dev->pci->dev, frame->mv.dma_addr, | ||
1334 | H264_MV_BUF_SIZE, DMA_FROM_DEVICE); | ||
1335 | spin_lock_irqsave(&dev->slock, flags); | ||
1336 | |||
1337 | dev->h264_buf_r_index++; | ||
1338 | dev->h264_buf_r_index %= H264_BUF_CNT; | ||
1339 | } | ||
1340 | spin_unlock_irqrestore(&dev->slock, flags); | ||
1341 | } | ||
1342 | |||
1343 | #ifdef DEBUG | ||
1344 | static u32 tw5864_vlc_checksum(u32 *data, int len) | ||
1345 | { | ||
1346 | u32 val, count_len = len; | ||
1347 | |||
1348 | val = *data++; | ||
1349 | while (((count_len >> 2) - 1) > 0) { | ||
1350 | val ^= *data++; | ||
1351 | count_len -= 4; | ||
1352 | } | ||
1353 | val ^= htonl((len >> 2)); | ||
1354 | return val; | ||
1355 | } | ||
1356 | #endif | ||
1357 | |||
1358 | static void tw5864_handle_frame(struct tw5864_h264_frame *frame) | ||
1359 | { | ||
1360 | #define SKIP_VLCBUF_BYTES 3 | ||
1361 | struct tw5864_input *input = frame->input; | ||
1362 | struct tw5864_dev *dev = input->root; | ||
1363 | struct tw5864_buf *vb; | ||
1364 | struct vb2_v4l2_buffer *v4l2_buf; | ||
1365 | int frame_len = frame->vlc_len - SKIP_VLCBUF_BYTES; | ||
1366 | u8 *dst = input->buf_cur_ptr; | ||
1367 | u8 tail_mask, vlc_mask = 0; | ||
1368 | int i; | ||
1369 | u8 vlc_first_byte = ((u8 *)(frame->vlc.addr + SKIP_VLCBUF_BYTES))[0]; | ||
1370 | unsigned long flags; | ||
1371 | int zero_run; | ||
1372 | u8 *src; | ||
1373 | u8 *src_end; | ||
1374 | |||
1375 | #ifdef DEBUG | ||
1376 | if (frame->checksum != | ||
1377 | tw5864_vlc_checksum((u32 *)frame->vlc.addr, frame_len)) | ||
1378 | dev_err(&dev->pci->dev, | ||
1379 | "Checksum of encoded frame doesn't match!\n"); | ||
1380 | #endif | ||
1381 | |||
1382 | spin_lock_irqsave(&input->slock, flags); | ||
1383 | vb = input->vb; | ||
1384 | input->vb = NULL; | ||
1385 | spin_unlock_irqrestore(&input->slock, flags); | ||
1386 | |||
1387 | v4l2_buf = to_vb2_v4l2_buffer(&vb->vb.vb2_buf); | ||
1388 | |||
1389 | if (!vb) { /* Gone because of disabling */ | ||
1390 | dev_dbg(&dev->pci->dev, "vb is empty, dropping frame\n"); | ||
1391 | return; | ||
1392 | } | ||
1393 | |||
1394 | /* | ||
1395 | * Check for space. | ||
1396 | * Mind the overhead of startcode emulation prevention. | ||
1397 | */ | ||
1398 | if (input->buf_cur_space_left < frame_len * 5 / 4) { | ||
1399 | dev_err_once(&dev->pci->dev, | ||
1400 | "Left space in vb2 buffer, %d bytes, is less than considered safely enough to put frame of length %d. Dropping this frame.\n", | ||
1401 | input->buf_cur_space_left, frame_len); | ||
1402 | return; | ||
1403 | } | ||
1404 | |||
1405 | for (i = 0; i < 8 - input->tail_nb_bits; i++) | ||
1406 | vlc_mask |= 1 << i; | ||
1407 | tail_mask = (~vlc_mask) & 0xff; | ||
1408 | |||
1409 | dst[0] = (input->tail & tail_mask) | (vlc_first_byte & vlc_mask); | ||
1410 | frame_len--; | ||
1411 | dst++; | ||
1412 | |||
1413 | /* H.264 startcode emulation prevention */ | ||
1414 | src = frame->vlc.addr + SKIP_VLCBUF_BYTES + 1; | ||
1415 | src_end = src + frame_len; | ||
1416 | zero_run = 0; | ||
1417 | for (; src < src_end; src++) { | ||
1418 | if (zero_run < 2) { | ||
1419 | if (*src == 0) | ||
1420 | ++zero_run; | ||
1421 | else | ||
1422 | zero_run = 0; | ||
1423 | } else { | ||
1424 | if ((*src & ~0x03) == 0) | ||
1425 | *dst++ = 0x03; | ||
1426 | zero_run = *src == 0; | ||
1427 | } | ||
1428 | *dst++ = *src; | ||
1429 | } | ||
1430 | |||
1431 | vb2_set_plane_payload(&vb->vb.vb2_buf, 0, | ||
1432 | dst - (u8 *)vb2_plane_vaddr(&vb->vb.vb2_buf, 0)); | ||
1433 | |||
1434 | vb->vb.vb2_buf.timestamp = frame->timestamp; | ||
1435 | v4l2_buf->field = V4L2_FIELD_INTERLACED; | ||
1436 | v4l2_buf->sequence = frame->seqno; | ||
1437 | |||
1438 | /* Check for motion flags */ | ||
1439 | if (frame->gop_seqno /* P-frame */ && | ||
1440 | tw5864_is_motion_triggered(frame)) { | ||
1441 | struct v4l2_event ev = { | ||
1442 | .type = V4L2_EVENT_MOTION_DET, | ||
1443 | .u.motion_det = { | ||
1444 | .flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ, | ||
1445 | .frame_sequence = v4l2_buf->sequence, | ||
1446 | }, | ||
1447 | }; | ||
1448 | |||
1449 | v4l2_event_queue(&input->vdev, &ev); | ||
1450 | } | ||
1451 | |||
1452 | vb2_buffer_done(&vb->vb.vb2_buf, VB2_BUF_STATE_DONE); | ||
1453 | } | ||
1454 | |||
1455 | static v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std) | ||
1456 | { | ||
1457 | switch (std) { | ||
1458 | case STD_NTSC: return V4L2_STD_NTSC_M; | ||
1459 | case STD_PAL: return V4L2_STD_PAL_B; | ||
1460 | case STD_SECAM: return V4L2_STD_SECAM_B; | ||
1461 | case STD_NTSC443: return V4L2_STD_NTSC_443; | ||
1462 | case STD_PAL_M: return V4L2_STD_PAL_M; | ||
1463 | case STD_PAL_CN: return V4L2_STD_PAL_Nc; | ||
1464 | case STD_PAL_60: return V4L2_STD_PAL_60; | ||
1465 | case STD_INVALID: return V4L2_STD_UNKNOWN; | ||
1466 | } | ||
1467 | return 0; | ||
1468 | } | ||
1469 | |||
1470 | static enum tw5864_vid_std tw5864_from_v4l2_std(v4l2_std_id v4l2_std) | ||
1471 | { | ||
1472 | if (v4l2_std & V4L2_STD_NTSC_M) | ||
1473 | return STD_NTSC; | ||
1474 | if (v4l2_std & V4L2_STD_PAL_B) | ||
1475 | return STD_PAL; | ||
1476 | if (v4l2_std & V4L2_STD_SECAM_B) | ||
1477 | return STD_SECAM; | ||
1478 | if (v4l2_std & V4L2_STD_NTSC_443) | ||
1479 | return STD_NTSC443; | ||
1480 | if (v4l2_std & V4L2_STD_PAL_M) | ||
1481 | return STD_PAL_M; | ||
1482 | if (v4l2_std & V4L2_STD_PAL_Nc) | ||
1483 | return STD_PAL_CN; | ||
1484 | if (v4l2_std & V4L2_STD_PAL_60) | ||
1485 | return STD_PAL_60; | ||
1486 | |||
1487 | return STD_INVALID; | ||
1488 | } | ||
1489 | |||
1490 | static void tw5864_encoder_tables_upload(struct tw5864_dev *dev) | ||
1491 | { | ||
1492 | int i; | ||
1493 | |||
1494 | tw_writel(TW5864_VLC_RD, 0x1); | ||
1495 | for (i = 0; i < VLC_LOOKUP_TABLE_LEN; i++) { | ||
1496 | tw_writel((TW5864_VLC_STREAM_MEM_START + i * 4), | ||
1497 | encoder_vlc_lookup_table[i]); | ||
1498 | } | ||
1499 | tw_writel(TW5864_VLC_RD, 0x0); | ||
1500 | |||
1501 | for (i = 0; i < QUANTIZATION_TABLE_LEN; i++) { | ||
1502 | tw_writel((TW5864_QUAN_TAB + i * 4), | ||
1503 | forward_quantization_table[i]); | ||
1504 | } | ||
1505 | |||
1506 | for (i = 0; i < QUANTIZATION_TABLE_LEN; i++) { | ||
1507 | tw_writel((TW5864_QUAN_TAB + i * 4), | ||
1508 | inverse_quantization_table[i]); | ||
1509 | } | ||
1510 | } | ||
diff --git a/drivers/media/pci/tw5864/tw5864.h b/drivers/media/pci/tw5864/tw5864.h new file mode 100644 index 000000000000..f5de9f6ef119 --- /dev/null +++ b/drivers/media/pci/tw5864/tw5864.h | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | * TW5864 driver - common header file | ||
3 | * | ||
4 | * Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/pci.h> | ||
18 | #include <linux/videodev2.h> | ||
19 | #include <linux/notifier.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/mutex.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | |||
25 | #include <media/v4l2-common.h> | ||
26 | #include <media/v4l2-ioctl.h> | ||
27 | #include <media/v4l2-ctrls.h> | ||
28 | #include <media/v4l2-device.h> | ||
29 | #include <media/videobuf2-dma-sg.h> | ||
30 | |||
31 | #include "tw5864-reg.h" | ||
32 | |||
33 | #define PCI_DEVICE_ID_TECHWELL_5864 0x5864 | ||
34 | |||
35 | #define TW5864_NORMS V4L2_STD_ALL | ||
36 | |||
37 | /* ----------------------------------------------------------- */ | ||
38 | /* card configuration */ | ||
39 | |||
40 | #define TW5864_INPUTS 4 | ||
41 | |||
42 | /* The TW5864 uses 192 (16x12) detection cells in full screen for motion | ||
43 | * detection. Each detection cell is composed of 44 pixels and 20 lines for | ||
44 | * NTSC and 24 lines for PAL. | ||
45 | */ | ||
46 | #define MD_CELLS_HOR 16 | ||
47 | #define MD_CELLS_VERT 12 | ||
48 | #define MD_CELLS (MD_CELLS_HOR * MD_CELLS_VERT) | ||
49 | |||
50 | #define H264_VLC_BUF_SIZE 0x80000 | ||
51 | #define H264_MV_BUF_SIZE 0x2000 /* device writes 5396 bytes */ | ||
52 | #define QP_VALUE 28 | ||
53 | #define MAX_GOP_SIZE 255 | ||
54 | #define GOP_SIZE MAX_GOP_SIZE | ||
55 | |||
56 | enum resolution { | ||
57 | D1 = 1, | ||
58 | HD1 = 2, /* half d1 - 360x(240|288) */ | ||
59 | CIF = 3, | ||
60 | QCIF = 4, | ||
61 | }; | ||
62 | |||
63 | /* ----------------------------------------------------------- */ | ||
64 | /* device / file handle status */ | ||
65 | |||
66 | struct tw5864_dev; /* forward delclaration */ | ||
67 | |||
68 | /* buffer for one video/vbi/ts frame */ | ||
69 | struct tw5864_buf { | ||
70 | struct vb2_v4l2_buffer vb; | ||
71 | struct list_head list; | ||
72 | |||
73 | unsigned int size; | ||
74 | }; | ||
75 | |||
76 | struct tw5864_dma_buf { | ||
77 | void *addr; | ||
78 | dma_addr_t dma_addr; | ||
79 | }; | ||
80 | |||
81 | enum tw5864_vid_std { | ||
82 | STD_NTSC = 0, /* NTSC (M) */ | ||
83 | STD_PAL = 1, /* PAL (B, D, G, H, I) */ | ||
84 | STD_SECAM = 2, /* SECAM */ | ||
85 | STD_NTSC443 = 3, /* NTSC4.43 */ | ||
86 | STD_PAL_M = 4, /* PAL (M) */ | ||
87 | STD_PAL_CN = 5, /* PAL (CN) */ | ||
88 | STD_PAL_60 = 6, /* PAL 60 */ | ||
89 | STD_INVALID = 7, | ||
90 | STD_AUTO = 7, | ||
91 | }; | ||
92 | |||
93 | struct tw5864_input { | ||
94 | int nr; /* input number */ | ||
95 | struct tw5864_dev *root; | ||
96 | struct mutex lock; /* used for vidq and vdev */ | ||
97 | spinlock_t slock; /* used for sync between ISR, tasklet & V4L2 API */ | ||
98 | struct video_device vdev; | ||
99 | struct v4l2_ctrl_handler hdl; | ||
100 | struct vb2_queue vidq; | ||
101 | struct list_head active; | ||
102 | enum resolution resolution; | ||
103 | unsigned int width, height; | ||
104 | unsigned int frame_seqno; | ||
105 | unsigned int frame_gop_seqno; | ||
106 | unsigned int h264_idr_pic_id; | ||
107 | int enabled; | ||
108 | enum tw5864_vid_std std; | ||
109 | v4l2_std_id v4l2_std; | ||
110 | int tail_nb_bits; | ||
111 | u8 tail; | ||
112 | u8 *buf_cur_ptr; | ||
113 | int buf_cur_space_left; | ||
114 | |||
115 | u32 reg_interlacing; | ||
116 | u32 reg_vlc; | ||
117 | u32 reg_dsp_codec; | ||
118 | u32 reg_dsp; | ||
119 | u32 reg_emu; | ||
120 | u32 reg_dsp_qp; | ||
121 | u32 reg_dsp_ref_mvp_lambda; | ||
122 | u32 reg_dsp_i4x4_weight; | ||
123 | u32 buf_id; | ||
124 | |||
125 | struct tw5864_buf *vb; | ||
126 | |||
127 | struct v4l2_ctrl *md_threshold_grid_ctrl; | ||
128 | u16 md_threshold_grid_values[12 * 16]; | ||
129 | int qp; | ||
130 | int gop; | ||
131 | |||
132 | /* | ||
133 | * In (1/MAX_FPS) units. | ||
134 | * For max FPS (default), set to 1. | ||
135 | * For 1 FPS, set to e.g. 32. | ||
136 | */ | ||
137 | int frame_interval; | ||
138 | unsigned long new_frame_deadline; | ||
139 | }; | ||
140 | |||
141 | struct tw5864_h264_frame { | ||
142 | struct tw5864_dma_buf vlc; | ||
143 | struct tw5864_dma_buf mv; | ||
144 | int vlc_len; | ||
145 | u32 checksum; | ||
146 | struct tw5864_input *input; | ||
147 | u64 timestamp; | ||
148 | unsigned int seqno; | ||
149 | unsigned int gop_seqno; | ||
150 | }; | ||
151 | |||
152 | /* global device status */ | ||
153 | struct tw5864_dev { | ||
154 | spinlock_t slock; /* used for sync between ISR, tasklet & V4L2 API */ | ||
155 | struct v4l2_device v4l2_dev; | ||
156 | struct tw5864_input inputs[TW5864_INPUTS]; | ||
157 | #define H264_BUF_CNT 4 | ||
158 | struct tw5864_h264_frame h264_buf[H264_BUF_CNT]; | ||
159 | int h264_buf_r_index; | ||
160 | int h264_buf_w_index; | ||
161 | |||
162 | struct tasklet_struct tasklet; | ||
163 | |||
164 | int encoder_busy; | ||
165 | /* Input number to check next for ready raw picture (in RR fashion) */ | ||
166 | int next_input; | ||
167 | |||
168 | /* pci i/o */ | ||
169 | char name[64]; | ||
170 | struct pci_dev *pci; | ||
171 | void __iomem *mmio; | ||
172 | u32 irqmask; | ||
173 | }; | ||
174 | |||
175 | #define tw_readl(reg) readl(dev->mmio + reg) | ||
176 | #define tw_mask_readl(reg, mask) \ | ||
177 | (tw_readl(reg) & (mask)) | ||
178 | #define tw_mask_shift_readl(reg, mask, shift) \ | ||
179 | (tw_mask_readl((reg), ((mask) << (shift))) >> (shift)) | ||
180 | |||
181 | #define tw_writel(reg, value) writel((value), dev->mmio + reg) | ||
182 | #define tw_mask_writel(reg, mask, value) \ | ||
183 | tw_writel(reg, (tw_readl(reg) & ~(mask)) | ((value) & (mask))) | ||
184 | #define tw_mask_shift_writel(reg, mask, shift, value) \ | ||
185 | tw_mask_writel((reg), ((mask) << (shift)), ((value) << (shift))) | ||
186 | |||
187 | #define tw_setl(reg, bit) tw_writel((reg), tw_readl(reg) | (bit)) | ||
188 | #define tw_clearl(reg, bit) tw_writel((reg), tw_readl(reg) & ~(bit)) | ||
189 | |||
190 | u8 tw5864_indir_readb(struct tw5864_dev *dev, u16 addr); | ||
191 | #define tw_indir_readb(addr) tw5864_indir_readb(dev, addr) | ||
192 | void tw5864_indir_writeb(struct tw5864_dev *dev, u16 addr, u8 data); | ||
193 | #define tw_indir_writeb(addr, data) tw5864_indir_writeb(dev, addr, data) | ||
194 | |||
195 | void tw5864_irqmask_apply(struct tw5864_dev *dev); | ||
196 | int tw5864_video_init(struct tw5864_dev *dev, int *video_nr); | ||
197 | void tw5864_video_fini(struct tw5864_dev *dev); | ||
198 | void tw5864_prepare_frame_headers(struct tw5864_input *input); | ||
199 | void tw5864_h264_put_stream_header(u8 **buf, size_t *space_left, int qp, | ||
200 | int width, int height); | ||
201 | void tw5864_h264_put_slice_header(u8 **buf, size_t *space_left, | ||
202 | unsigned int idr_pic_id, | ||
203 | unsigned int frame_gop_seqno, | ||
204 | int *tail_nb_bits, u8 *tail); | ||
205 | void tw5864_request_encoded_frame(struct tw5864_input *input); | ||
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 5e8212845c87..a45e02367321 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c | |||
@@ -535,7 +535,7 @@ static void tw68_stop_streaming(struct vb2_queue *q) | |||
535 | } | 535 | } |
536 | } | 536 | } |
537 | 537 | ||
538 | static struct vb2_ops tw68_video_qops = { | 538 | static const struct vb2_ops tw68_video_qops = { |
539 | .queue_setup = tw68_queue_setup, | 539 | .queue_setup = tw68_queue_setup, |
540 | .buf_queue = tw68_buf_queue, | 540 | .buf_queue = tw68_buf_queue, |
541 | .buf_prepare = tw68_buf_prepare, | 541 | .buf_prepare = tw68_buf_prepare, |
diff --git a/drivers/media/pci/tw686x/tw686x-audio.c b/drivers/media/pci/tw686x/tw686x-audio.c index 96e444c49173..77190768622a 100644 --- a/drivers/media/pci/tw686x/tw686x-audio.c +++ b/drivers/media/pci/tw686x/tw686x-audio.c | |||
@@ -269,7 +269,7 @@ static snd_pcm_uframes_t tw686x_pcm_pointer(struct snd_pcm_substream *ss) | |||
269 | return bytes_to_frames(ss->runtime, ac->ptr); | 269 | return bytes_to_frames(ss->runtime, ac->ptr); |
270 | } | 270 | } |
271 | 271 | ||
272 | static struct snd_pcm_ops tw686x_pcm_ops = { | 272 | static const struct snd_pcm_ops tw686x_pcm_ops = { |
273 | .open = tw686x_pcm_open, | 273 | .open = tw686x_pcm_open, |
274 | .close = tw686x_pcm_close, | 274 | .close = tw686x_pcm_close, |
275 | .ioctl = snd_pcm_lib_ioctl, | 275 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index cdb16de770fe..c3fafa97b2d0 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c | |||
@@ -577,7 +577,7 @@ static int tw686x_buf_prepare(struct vb2_buffer *vb) | |||
577 | return 0; | 577 | return 0; |
578 | } | 578 | } |
579 | 579 | ||
580 | static struct vb2_ops tw686x_video_qops = { | 580 | static const struct vb2_ops tw686x_video_qops = { |
581 | .queue_setup = tw686x_queue_setup, | 581 | .queue_setup = tw686x_queue_setup, |
582 | .buf_queue = tw686x_buf_queue, | 582 | .buf_queue = tw686x_buf_queue, |
583 | .buf_prepare = tw686x_buf_prepare, | 583 | .buf_prepare = tw686x_buf_prepare, |
@@ -672,30 +672,20 @@ static int tw686x_try_fmt_vid_cap(struct file *file, void *priv, | |||
672 | return 0; | 672 | return 0; |
673 | } | 673 | } |
674 | 674 | ||
675 | static int tw686x_s_fmt_vid_cap(struct file *file, void *priv, | 675 | static int tw686x_set_format(struct tw686x_video_channel *vc, |
676 | struct v4l2_format *f) | 676 | unsigned int pixelformat, unsigned int width, |
677 | unsigned int height, bool realloc) | ||
677 | { | 678 | { |
678 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
679 | struct tw686x_dev *dev = vc->dev; | 679 | struct tw686x_dev *dev = vc->dev; |
680 | u32 val, width, line_width, height; | 680 | u32 val, dma_width, dma_height, dma_line_width; |
681 | unsigned long bitsperframe; | ||
682 | int err, pb; | 681 | int err, pb; |
683 | 682 | ||
684 | if (vb2_is_busy(&vc->vidq)) | 683 | vc->format = format_by_fourcc(pixelformat); |
685 | return -EBUSY; | 684 | vc->width = width; |
686 | 685 | vc->height = height; | |
687 | bitsperframe = vc->width * vc->height * vc->format->depth; | ||
688 | err = tw686x_try_fmt_vid_cap(file, priv, f); | ||
689 | if (err) | ||
690 | return err; | ||
691 | |||
692 | vc->format = format_by_fourcc(f->fmt.pix.pixelformat); | ||
693 | vc->width = f->fmt.pix.width; | ||
694 | vc->height = f->fmt.pix.height; | ||
695 | 686 | ||
696 | /* We need new DMA buffers if the framesize has changed */ | 687 | /* We need new DMA buffers if the framesize has changed */ |
697 | if (dev->dma_ops->alloc && | 688 | if (dev->dma_ops->alloc && realloc) { |
698 | bitsperframe != vc->width * vc->height * vc->format->depth) { | ||
699 | for (pb = 0; pb < 2; pb++) | 689 | for (pb = 0; pb < 2; pb++) |
700 | dev->dma_ops->free(vc, pb); | 690 | dev->dma_ops->free(vc, pb); |
701 | 691 | ||
@@ -739,14 +729,36 @@ static int tw686x_s_fmt_vid_cap(struct file *file, void *priv, | |||
739 | reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val); | 729 | reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val); |
740 | 730 | ||
741 | /* Program the DMA frame size */ | 731 | /* Program the DMA frame size */ |
742 | width = (vc->width * 2) & 0x7ff; | 732 | dma_width = (vc->width * 2) & 0x7ff; |
743 | height = vc->height / 2; | 733 | dma_height = vc->height / 2; |
744 | line_width = (vc->width * 2) & 0x7ff; | 734 | dma_line_width = (vc->width * 2) & 0x7ff; |
745 | val = (height << 22) | (line_width << 11) | width; | 735 | val = (dma_height << 22) | (dma_line_width << 11) | dma_width; |
746 | reg_write(vc->dev, VDMA_WHP[vc->ch], val); | 736 | reg_write(vc->dev, VDMA_WHP[vc->ch], val); |
747 | return 0; | 737 | return 0; |
748 | } | 738 | } |
749 | 739 | ||
740 | static int tw686x_s_fmt_vid_cap(struct file *file, void *priv, | ||
741 | struct v4l2_format *f) | ||
742 | { | ||
743 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
744 | unsigned long area; | ||
745 | bool realloc; | ||
746 | int err; | ||
747 | |||
748 | if (vb2_is_busy(&vc->vidq)) | ||
749 | return -EBUSY; | ||
750 | |||
751 | area = vc->width * vc->height; | ||
752 | err = tw686x_try_fmt_vid_cap(file, priv, f); | ||
753 | if (err) | ||
754 | return err; | ||
755 | |||
756 | realloc = area != (f->fmt.pix.width * f->fmt.pix.height); | ||
757 | return tw686x_set_format(vc, f->fmt.pix.pixelformat, | ||
758 | f->fmt.pix.width, f->fmt.pix.height, | ||
759 | realloc); | ||
760 | } | ||
761 | |||
750 | static int tw686x_querycap(struct file *file, void *priv, | 762 | static int tw686x_querycap(struct file *file, void *priv, |
751 | struct v4l2_capability *cap) | 763 | struct v4l2_capability *cap) |
752 | { | 764 | { |
@@ -763,17 +775,9 @@ static int tw686x_querycap(struct file *file, void *priv, | |||
763 | return 0; | 775 | return 0; |
764 | } | 776 | } |
765 | 777 | ||
766 | static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id) | 778 | static int tw686x_set_standard(struct tw686x_video_channel *vc, v4l2_std_id id) |
767 | { | 779 | { |
768 | struct tw686x_video_channel *vc = video_drvdata(file); | 780 | u32 val; |
769 | struct v4l2_format f; | ||
770 | u32 val, ret; | ||
771 | |||
772 | if (vc->video_standard == id) | ||
773 | return 0; | ||
774 | |||
775 | if (vb2_is_busy(&vc->vidq)) | ||
776 | return -EBUSY; | ||
777 | 781 | ||
778 | if (id & V4L2_STD_NTSC) | 782 | if (id & V4L2_STD_NTSC) |
779 | val = 0; | 783 | val = 0; |
@@ -802,14 +806,31 @@ static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id) | |||
802 | val |= (1 << (SYS_MODE_DMA_SHIFT + vc->ch)); | 806 | val |= (1 << (SYS_MODE_DMA_SHIFT + vc->ch)); |
803 | reg_write(vc->dev, VIDEO_CONTROL1, val); | 807 | reg_write(vc->dev, VIDEO_CONTROL1, val); |
804 | 808 | ||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id) | ||
813 | { | ||
814 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
815 | struct v4l2_format f; | ||
816 | int ret; | ||
817 | |||
818 | if (vc->video_standard == id) | ||
819 | return 0; | ||
820 | |||
821 | if (vb2_is_busy(&vc->vidq)) | ||
822 | return -EBUSY; | ||
823 | |||
824 | ret = tw686x_set_standard(vc, id); | ||
825 | if (ret) | ||
826 | return ret; | ||
805 | /* | 827 | /* |
806 | * Adjust format after V4L2_STD_525_60/V4L2_STD_625_50 change, | 828 | * Adjust format after V4L2_STD_525_60/V4L2_STD_625_50 change, |
807 | * calling g_fmt and s_fmt will sanitize the height | 829 | * calling g_fmt and s_fmt will sanitize the height |
808 | * according to the standard. | 830 | * according to the standard. |
809 | */ | 831 | */ |
810 | ret = tw686x_g_fmt_vid_cap(file, priv, &f); | 832 | tw686x_g_fmt_vid_cap(file, priv, &f); |
811 | if (!ret) | 833 | tw686x_s_fmt_vid_cap(file, priv, &f); |
812 | tw686x_s_fmt_vid_cap(file, priv, &f); | ||
813 | 834 | ||
814 | /* | 835 | /* |
815 | * Frame decimation depends on the chosen standard, | 836 | * Frame decimation depends on the chosen standard, |
@@ -885,6 +906,42 @@ static int tw686x_g_std(struct file *file, void *priv, v4l2_std_id *id) | |||
885 | return 0; | 906 | return 0; |
886 | } | 907 | } |
887 | 908 | ||
909 | static int tw686x_enum_framesizes(struct file *file, void *priv, | ||
910 | struct v4l2_frmsizeenum *fsize) | ||
911 | { | ||
912 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
913 | |||
914 | if (fsize->index) | ||
915 | return -EINVAL; | ||
916 | fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; | ||
917 | fsize->stepwise.max_width = TW686X_VIDEO_WIDTH; | ||
918 | fsize->stepwise.min_width = fsize->stepwise.max_width / 2; | ||
919 | fsize->stepwise.step_width = fsize->stepwise.min_width; | ||
920 | fsize->stepwise.max_height = TW686X_VIDEO_HEIGHT(vc->video_standard); | ||
921 | fsize->stepwise.min_height = fsize->stepwise.max_height / 2; | ||
922 | fsize->stepwise.step_height = fsize->stepwise.min_height; | ||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | static int tw686x_enum_frameintervals(struct file *file, void *priv, | ||
927 | struct v4l2_frmivalenum *ival) | ||
928 | { | ||
929 | struct tw686x_video_channel *vc = video_drvdata(file); | ||
930 | int max_fps = TW686X_MAX_FPS(vc->video_standard); | ||
931 | int max_rates = DIV_ROUND_UP(max_fps, 2); | ||
932 | |||
933 | if (ival->index >= max_rates) | ||
934 | return -EINVAL; | ||
935 | |||
936 | ival->type = V4L2_FRMIVAL_TYPE_DISCRETE; | ||
937 | ival->discrete.numerator = 1; | ||
938 | if (ival->index < (max_rates - 1)) | ||
939 | ival->discrete.denominator = (ival->index + 1) * 2; | ||
940 | else | ||
941 | ival->discrete.denominator = max_fps; | ||
942 | return 0; | ||
943 | } | ||
944 | |||
888 | static int tw686x_g_parm(struct file *file, void *priv, | 945 | static int tw686x_g_parm(struct file *file, void *priv, |
889 | struct v4l2_streamparm *sp) | 946 | struct v4l2_streamparm *sp) |
890 | { | 947 | { |
@@ -928,10 +985,21 @@ static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv, | |||
928 | return 0; | 985 | return 0; |
929 | } | 986 | } |
930 | 987 | ||
988 | static void tw686x_set_input(struct tw686x_video_channel *vc, unsigned int i) | ||
989 | { | ||
990 | u32 val; | ||
991 | |||
992 | vc->input = i; | ||
993 | |||
994 | val = reg_read(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch]); | ||
995 | val &= ~(0x3 << 30); | ||
996 | val |= i << 30; | ||
997 | reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val); | ||
998 | } | ||
999 | |||
931 | static int tw686x_s_input(struct file *file, void *priv, unsigned int i) | 1000 | static int tw686x_s_input(struct file *file, void *priv, unsigned int i) |
932 | { | 1001 | { |
933 | struct tw686x_video_channel *vc = video_drvdata(file); | 1002 | struct tw686x_video_channel *vc = video_drvdata(file); |
934 | u32 val; | ||
935 | 1003 | ||
936 | if (i >= TW686X_INPUTS_PER_CH) | 1004 | if (i >= TW686X_INPUTS_PER_CH) |
937 | return -EINVAL; | 1005 | return -EINVAL; |
@@ -943,12 +1011,7 @@ static int tw686x_s_input(struct file *file, void *priv, unsigned int i) | |||
943 | if (vb2_is_busy(&vc->vidq)) | 1011 | if (vb2_is_busy(&vc->vidq)) |
944 | return -EBUSY; | 1012 | return -EBUSY; |
945 | 1013 | ||
946 | vc->input = i; | 1014 | tw686x_set_input(vc, i); |
947 | |||
948 | val = reg_read(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch]); | ||
949 | val &= ~(0x3 << 30); | ||
950 | val |= i << 30; | ||
951 | reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val); | ||
952 | return 0; | 1015 | return 0; |
953 | } | 1016 | } |
954 | 1017 | ||
@@ -1007,6 +1070,8 @@ static const struct v4l2_ioctl_ops tw686x_video_ioctl_ops = { | |||
1007 | 1070 | ||
1008 | .vidioc_g_parm = tw686x_g_parm, | 1071 | .vidioc_g_parm = tw686x_g_parm, |
1009 | .vidioc_s_parm = tw686x_s_parm, | 1072 | .vidioc_s_parm = tw686x_s_parm, |
1073 | .vidioc_enum_framesizes = tw686x_enum_framesizes, | ||
1074 | .vidioc_enum_frameintervals = tw686x_enum_frameintervals, | ||
1010 | 1075 | ||
1011 | .vidioc_enum_input = tw686x_enum_input, | 1076 | .vidioc_enum_input = tw686x_enum_input, |
1012 | .vidioc_g_input = tw686x_g_input, | 1077 | .vidioc_g_input = tw686x_g_input, |
@@ -1093,8 +1158,7 @@ void tw686x_video_free(struct tw686x_dev *dev) | |||
1093 | for (ch = 0; ch < max_channels(dev); ch++) { | 1158 | for (ch = 0; ch < max_channels(dev); ch++) { |
1094 | struct tw686x_video_channel *vc = &dev->video_channels[ch]; | 1159 | struct tw686x_video_channel *vc = &dev->video_channels[ch]; |
1095 | 1160 | ||
1096 | if (vc->device) | 1161 | video_unregister_device(vc->device); |
1097 | video_unregister_device(vc->device); | ||
1098 | 1162 | ||
1099 | if (dev->dma_ops->free) | 1163 | if (dev->dma_ops->free) |
1100 | for (pb = 0; pb < 2; pb++) | 1164 | for (pb = 0; pb < 2; pb++) |
@@ -1104,7 +1168,7 @@ void tw686x_video_free(struct tw686x_dev *dev) | |||
1104 | 1168 | ||
1105 | int tw686x_video_init(struct tw686x_dev *dev) | 1169 | int tw686x_video_init(struct tw686x_dev *dev) |
1106 | { | 1170 | { |
1107 | unsigned int ch, val, pb; | 1171 | unsigned int ch, val; |
1108 | int err; | 1172 | int err; |
1109 | 1173 | ||
1110 | if (dev->dma_mode == TW686X_DMA_MODE_MEMCPY) | 1174 | if (dev->dma_mode == TW686X_DMA_MODE_MEMCPY) |
@@ -1138,27 +1202,23 @@ int tw686x_video_init(struct tw686x_dev *dev) | |||
1138 | vc->ch = ch; | 1202 | vc->ch = ch; |
1139 | 1203 | ||
1140 | /* default settings */ | 1204 | /* default settings */ |
1141 | vc->format = &formats[0]; | 1205 | err = tw686x_set_standard(vc, V4L2_STD_NTSC); |
1142 | vc->video_standard = V4L2_STD_NTSC; | 1206 | if (err) |
1143 | vc->width = TW686X_VIDEO_WIDTH; | 1207 | goto error; |
1144 | vc->height = TW686X_VIDEO_HEIGHT(vc->video_standard); | ||
1145 | vc->input = 0; | ||
1146 | 1208 | ||
1147 | reg_write(vc->dev, SDT[ch], 0); | 1209 | err = tw686x_set_format(vc, formats[0].fourcc, |
1148 | tw686x_set_framerate(vc, 30); | 1210 | TW686X_VIDEO_WIDTH, |
1211 | TW686X_VIDEO_HEIGHT(vc->video_standard), | ||
1212 | true); | ||
1213 | if (err) | ||
1214 | goto error; | ||
1149 | 1215 | ||
1216 | tw686x_set_input(vc, 0); | ||
1217 | tw686x_set_framerate(vc, 30); | ||
1150 | reg_write(dev, VDELAY_LO[ch], 0x14); | 1218 | reg_write(dev, VDELAY_LO[ch], 0x14); |
1151 | reg_write(dev, HACTIVE_LO[ch], 0xd0); | 1219 | reg_write(dev, HACTIVE_LO[ch], 0xd0); |
1152 | reg_write(dev, VIDEO_SIZE[ch], 0); | 1220 | reg_write(dev, VIDEO_SIZE[ch], 0); |
1153 | 1221 | ||
1154 | if (dev->dma_ops->alloc) { | ||
1155 | for (pb = 0; pb < 2; pb++) { | ||
1156 | err = dev->dma_ops->alloc(vc, pb); | ||
1157 | if (err) | ||
1158 | goto error; | ||
1159 | } | ||
1160 | } | ||
1161 | |||
1162 | vc->vidq.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF; | 1222 | vc->vidq.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF; |
1163 | vc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1223 | vc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1164 | vc->vidq.drv_priv = vc; | 1224 | vc->vidq.drv_priv = vc; |
diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index 80caa70c6360..d6b631add216 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c | |||
@@ -2365,94 +2365,80 @@ static int zoran_s_output(struct file *file, void *__fh, unsigned int output) | |||
2365 | } | 2365 | } |
2366 | 2366 | ||
2367 | /* cropping (sub-frame capture) */ | 2367 | /* cropping (sub-frame capture) */ |
2368 | static int zoran_cropcap(struct file *file, void *__fh, | 2368 | static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selection *sel) |
2369 | struct v4l2_cropcap *cropcap) | ||
2370 | { | 2369 | { |
2371 | struct zoran_fh *fh = __fh; | 2370 | struct zoran_fh *fh = __fh; |
2372 | struct zoran *zr = fh->zr; | 2371 | struct zoran *zr = fh->zr; |
2373 | int type = cropcap->type, res = 0; | ||
2374 | 2372 | ||
2375 | memset(cropcap, 0, sizeof(*cropcap)); | 2373 | if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && |
2376 | cropcap->type = type; | 2374 | sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
2375 | return -EINVAL; | ||
2377 | 2376 | ||
2378 | if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && | 2377 | if (fh->map_mode == ZORAN_MAP_MODE_RAW) { |
2379 | (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2380 | fh->map_mode == ZORAN_MAP_MODE_RAW)) { | ||
2381 | dprintk(1, KERN_ERR | 2378 | dprintk(1, KERN_ERR |
2382 | "%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n", | 2379 | "%s: VIDIOC_G_SELECTION - subcapture only supported for compressed capture\n", |
2383 | ZR_DEVNAME(zr)); | 2380 | ZR_DEVNAME(zr)); |
2384 | res = -EINVAL; | 2381 | return -EINVAL; |
2385 | return res; | ||
2386 | } | 2382 | } |
2387 | 2383 | ||
2388 | cropcap->bounds.top = cropcap->bounds.left = 0; | 2384 | switch (sel->target) { |
2389 | cropcap->bounds.width = BUZ_MAX_WIDTH; | 2385 | case V4L2_SEL_TGT_CROP: |
2390 | cropcap->bounds.height = BUZ_MAX_HEIGHT; | 2386 | sel->r.top = fh->jpg_settings.img_y; |
2391 | cropcap->defrect.top = cropcap->defrect.left = 0; | 2387 | sel->r.left = fh->jpg_settings.img_x; |
2392 | cropcap->defrect.width = BUZ_MIN_WIDTH; | 2388 | sel->r.width = fh->jpg_settings.img_width; |
2393 | cropcap->defrect.height = BUZ_MIN_HEIGHT; | 2389 | sel->r.height = fh->jpg_settings.img_height; |
2394 | return res; | 2390 | break; |
2395 | } | 2391 | case V4L2_SEL_TGT_CROP_DEFAULT: |
2396 | 2392 | sel->r.top = sel->r.left = 0; | |
2397 | static int zoran_g_crop(struct file *file, void *__fh, struct v4l2_crop *crop) | 2393 | sel->r.width = BUZ_MIN_WIDTH; |
2398 | { | 2394 | sel->r.height = BUZ_MIN_HEIGHT; |
2399 | struct zoran_fh *fh = __fh; | 2395 | break; |
2400 | struct zoran *zr = fh->zr; | 2396 | case V4L2_SEL_TGT_CROP_BOUNDS: |
2401 | int type = crop->type, res = 0; | 2397 | sel->r.top = sel->r.left = 0; |
2402 | 2398 | sel->r.width = BUZ_MAX_WIDTH; | |
2403 | memset(crop, 0, sizeof(*crop)); | 2399 | sel->r.height = BUZ_MAX_HEIGHT; |
2404 | crop->type = type; | 2400 | break; |
2405 | 2401 | default: | |
2406 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && | 2402 | return -EINVAL; |
2407 | (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2408 | fh->map_mode == ZORAN_MAP_MODE_RAW)) { | ||
2409 | dprintk(1, | ||
2410 | KERN_ERR | ||
2411 | "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n", | ||
2412 | ZR_DEVNAME(zr)); | ||
2413 | res = -EINVAL; | ||
2414 | return res; | ||
2415 | } | 2403 | } |
2416 | 2404 | return 0; | |
2417 | crop->c.top = fh->jpg_settings.img_y; | ||
2418 | crop->c.left = fh->jpg_settings.img_x; | ||
2419 | crop->c.width = fh->jpg_settings.img_width; | ||
2420 | crop->c.height = fh->jpg_settings.img_height; | ||
2421 | return res; | ||
2422 | } | 2405 | } |
2423 | 2406 | ||
2424 | static int zoran_s_crop(struct file *file, void *__fh, const struct v4l2_crop *crop) | 2407 | static int zoran_s_selection(struct file *file, void *__fh, struct v4l2_selection *sel) |
2425 | { | 2408 | { |
2426 | struct zoran_fh *fh = __fh; | 2409 | struct zoran_fh *fh = __fh; |
2427 | struct zoran *zr = fh->zr; | 2410 | struct zoran *zr = fh->zr; |
2428 | int res = 0; | ||
2429 | struct zoran_jpg_settings settings; | 2411 | struct zoran_jpg_settings settings; |
2412 | int res; | ||
2430 | 2413 | ||
2431 | settings = fh->jpg_settings; | 2414 | if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && |
2415 | sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2416 | return -EINVAL; | ||
2432 | 2417 | ||
2433 | if (fh->buffers.allocated) { | 2418 | if (sel->target != V4L2_SEL_TGT_CROP) |
2419 | return -EINVAL; | ||
2420 | |||
2421 | if (fh->map_mode == ZORAN_MAP_MODE_RAW) { | ||
2434 | dprintk(1, KERN_ERR | 2422 | dprintk(1, KERN_ERR |
2435 | "%s: VIDIOC_S_CROP - cannot change settings while active\n", | 2423 | "%s: VIDIOC_S_SELECTION - subcapture only supported for compressed capture\n", |
2436 | ZR_DEVNAME(zr)); | 2424 | ZR_DEVNAME(zr)); |
2437 | res = -EBUSY; | 2425 | return -EINVAL; |
2438 | return res; | ||
2439 | } | 2426 | } |
2440 | 2427 | ||
2441 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && | 2428 | settings = fh->jpg_settings; |
2442 | (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | 2429 | |
2443 | fh->map_mode == ZORAN_MAP_MODE_RAW)) { | 2430 | if (fh->buffers.allocated) { |
2444 | dprintk(1, KERN_ERR | 2431 | dprintk(1, KERN_ERR |
2445 | "%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n", | 2432 | "%s: VIDIOC_S_SELECTION - cannot change settings while active\n", |
2446 | ZR_DEVNAME(zr)); | 2433 | ZR_DEVNAME(zr)); |
2447 | res = -EINVAL; | 2434 | return -EBUSY; |
2448 | return res; | ||
2449 | } | 2435 | } |
2450 | 2436 | ||
2451 | /* move into a form that we understand */ | 2437 | /* move into a form that we understand */ |
2452 | settings.img_x = crop->c.left; | 2438 | settings.img_x = sel->r.left; |
2453 | settings.img_y = crop->c.top; | 2439 | settings.img_y = sel->r.top; |
2454 | settings.img_width = crop->c.width; | 2440 | settings.img_width = sel->r.width; |
2455 | settings.img_height = crop->c.height; | 2441 | settings.img_height = sel->r.height; |
2456 | 2442 | ||
2457 | /* check validity */ | 2443 | /* check validity */ |
2458 | res = zoran_check_jpg_settings(zr, &settings, 0); | 2444 | res = zoran_check_jpg_settings(zr, &settings, 0); |
@@ -2808,9 +2794,8 @@ zoran_mmap (struct file *file, | |||
2808 | 2794 | ||
2809 | static const struct v4l2_ioctl_ops zoran_ioctl_ops = { | 2795 | static const struct v4l2_ioctl_ops zoran_ioctl_ops = { |
2810 | .vidioc_querycap = zoran_querycap, | 2796 | .vidioc_querycap = zoran_querycap, |
2811 | .vidioc_cropcap = zoran_cropcap, | 2797 | .vidioc_s_selection = zoran_s_selection, |
2812 | .vidioc_s_crop = zoran_s_crop, | 2798 | .vidioc_g_selection = zoran_g_selection, |
2813 | .vidioc_g_crop = zoran_g_crop, | ||
2814 | .vidioc_enum_input = zoran_enum_input, | 2799 | .vidioc_enum_input = zoran_enum_input, |
2815 | .vidioc_g_input = zoran_g_input, | 2800 | .vidioc_g_input = zoran_g_input, |
2816 | .vidioc_s_input = zoran_s_input, | 2801 | .vidioc_s_input = zoran_s_input, |
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 552b635cfce7..ce4a96fccc43 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig | |||
@@ -91,6 +91,15 @@ config VIDEO_OMAP3_DEBUG | |||
91 | ---help--- | 91 | ---help--- |
92 | Enable debug messages on OMAP 3 camera controller driver. | 92 | Enable debug messages on OMAP 3 camera controller driver. |
93 | 93 | ||
94 | config VIDEO_PXA27x | ||
95 | tristate "PXA27x Quick Capture Interface driver" | ||
96 | depends on VIDEO_DEV && HAS_DMA | ||
97 | depends on PXA27x || COMPILE_TEST | ||
98 | select VIDEOBUF2_DMA_SG | ||
99 | select SG_SPLIT | ||
100 | ---help--- | ||
101 | This is a v4l2 driver for the PXA27x Quick Capture Interface | ||
102 | |||
94 | config VIDEO_S3C_CAMIF | 103 | config VIDEO_S3C_CAMIF |
95 | tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver" | 104 | tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver" |
96 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API | 105 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
@@ -107,10 +116,10 @@ config VIDEO_S3C_CAMIF | |||
107 | 116 | ||
108 | source "drivers/media/platform/soc_camera/Kconfig" | 117 | source "drivers/media/platform/soc_camera/Kconfig" |
109 | source "drivers/media/platform/exynos4-is/Kconfig" | 118 | source "drivers/media/platform/exynos4-is/Kconfig" |
110 | source "drivers/media/platform/s5p-tv/Kconfig" | ||
111 | source "drivers/media/platform/am437x/Kconfig" | 119 | source "drivers/media/platform/am437x/Kconfig" |
112 | source "drivers/media/platform/xilinx/Kconfig" | 120 | source "drivers/media/platform/xilinx/Kconfig" |
113 | source "drivers/media/platform/rcar-vin/Kconfig" | 121 | source "drivers/media/platform/rcar-vin/Kconfig" |
122 | source "drivers/media/platform/atmel/Kconfig" | ||
114 | 123 | ||
115 | config VIDEO_TI_CAL | 124 | config VIDEO_TI_CAL |
116 | tristate "TI CAL (Camera Adaptation Layer) driver" | 125 | tristate "TI CAL (Camera Adaptation Layer) driver" |
@@ -155,7 +164,7 @@ config VIDEO_CODA | |||
155 | 164 | ||
156 | config VIDEO_MEDIATEK_VPU | 165 | config VIDEO_MEDIATEK_VPU |
157 | tristate "Mediatek Video Processor Unit" | 166 | tristate "Mediatek Video Processor Unit" |
158 | depends on VIDEO_DEV && VIDEO_V4L2 | 167 | depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA |
159 | depends on ARCH_MEDIATEK || COMPILE_TEST | 168 | depends on ARCH_MEDIATEK || COMPILE_TEST |
160 | ---help--- | 169 | ---help--- |
161 | This driver provides downloading VPU firmware and | 170 | This driver provides downloading VPU firmware and |
@@ -257,6 +266,21 @@ config VIDEO_STI_BDISP | |||
257 | help | 266 | help |
258 | This v4l2 mem2mem driver is a 2D blitter for STMicroelectronics SoC. | 267 | This v4l2 mem2mem driver is a 2D blitter for STMicroelectronics SoC. |
259 | 268 | ||
269 | config VIDEO_STI_HVA | ||
270 | tristate "STMicroelectronics HVA multi-format video encoder V4L2 driver" | ||
271 | depends on VIDEO_DEV && VIDEO_V4L2 | ||
272 | depends on HAS_DMA | ||
273 | depends on ARCH_STI || COMPILE_TEST | ||
274 | select VIDEOBUF2_DMA_CONTIG | ||
275 | select V4L2_MEM2MEM_DEV | ||
276 | help | ||
277 | This V4L2 driver enables HVA (Hardware Video Accelerator) multi-format | ||
278 | video encoder of STMicroelectronics SoC, allowing hardware encoding of | ||
279 | raw uncompressed formats in various compressed video bitstreams format. | ||
280 | |||
281 | To compile this driver as a module, choose M here: | ||
282 | the module will be called st-hva. | ||
283 | |||
260 | config VIDEO_SH_VEU | 284 | config VIDEO_SH_VEU |
261 | tristate "SuperH VEU mem2mem video processing driver" | 285 | tristate "SuperH VEU mem2mem video processing driver" |
262 | depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA | 286 | depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA |
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 21771c1a13fb..40b18d12726e 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile | |||
@@ -9,6 +9,7 @@ obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/ | |||
9 | obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/ | 9 | obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/ |
10 | 10 | ||
11 | obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/ | 11 | obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/ |
12 | obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o | ||
12 | 13 | ||
13 | obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o | 14 | obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o |
14 | 15 | ||
@@ -30,12 +31,12 @@ obj-$(CONFIG_VIDEO_S3C_CAMIF) += s3c-camif/ | |||
30 | obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS) += exynos4-is/ | 31 | obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS) += exynos4-is/ |
31 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ | 32 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ |
32 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ | 33 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ |
33 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5p-tv/ | ||
34 | 34 | ||
35 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ | 35 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ |
36 | obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC) += exynos-gsc/ | 36 | obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC) += exynos-gsc/ |
37 | 37 | ||
38 | obj-$(CONFIG_VIDEO_STI_BDISP) += sti/bdisp/ | 38 | obj-$(CONFIG_VIDEO_STI_BDISP) += sti/bdisp/ |
39 | obj-$(CONFIG_VIDEO_STI_HVA) += sti/hva/ | ||
39 | obj-$(CONFIG_DVB_C8SECTPFE) += sti/c8sectpfe/ | 40 | obj-$(CONFIG_DVB_C8SECTPFE) += sti/c8sectpfe/ |
40 | 41 | ||
41 | obj-$(CONFIG_BLACKFIN) += blackfin/ | 42 | obj-$(CONFIG_BLACKFIN) += blackfin/ |
@@ -58,6 +59,8 @@ obj-$(CONFIG_VIDEO_XILINX) += xilinx/ | |||
58 | 59 | ||
59 | obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin/ | 60 | obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin/ |
60 | 61 | ||
62 | obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel/ | ||
63 | |||
61 | ccflags-y += -I$(srctree)/drivers/media/i2c | 64 | ccflags-y += -I$(srctree)/drivers/media/i2c |
62 | 65 | ||
63 | obj-$(CONFIG_VIDEO_MEDIATEK_VPU) += mtk-vpu/ | 66 | obj-$(CONFIG_VIDEO_MEDIATEK_VPU) += mtk-vpu/ |
diff --git a/drivers/media/platform/atmel/Kconfig b/drivers/media/platform/atmel/Kconfig new file mode 100644 index 000000000000..867dca22a473 --- /dev/null +++ b/drivers/media/platform/atmel/Kconfig | |||
@@ -0,0 +1,9 @@ | |||
1 | config VIDEO_ATMEL_ISC | ||
2 | tristate "ATMEL Image Sensor Controller (ISC) support" | ||
3 | depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API && HAS_DMA | ||
4 | depends on ARCH_AT91 || COMPILE_TEST | ||
5 | select VIDEOBUF2_DMA_CONTIG | ||
6 | select REGMAP_MMIO | ||
7 | help | ||
8 | This module makes the ATMEL Image Sensor Controller available | ||
9 | as a v4l2 device. \ No newline at end of file | ||
diff --git a/drivers/media/platform/atmel/Makefile b/drivers/media/platform/atmel/Makefile new file mode 100644 index 000000000000..9d7c999d434d --- /dev/null +++ b/drivers/media/platform/atmel/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o | |||
diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/media/platform/atmel/atmel-isc-regs.h new file mode 100644 index 000000000000..00c449717cde --- /dev/null +++ b/drivers/media/platform/atmel/atmel-isc-regs.h | |||
@@ -0,0 +1,165 @@ | |||
1 | #ifndef __ATMEL_ISC_REGS_H | ||
2 | #define __ATMEL_ISC_REGS_H | ||
3 | |||
4 | #include <linux/bitops.h> | ||
5 | |||
6 | /* ISC Control Enable Register 0 */ | ||
7 | #define ISC_CTRLEN 0x00000000 | ||
8 | |||
9 | /* ISC Control Disable Register 0 */ | ||
10 | #define ISC_CTRLDIS 0x00000004 | ||
11 | |||
12 | /* ISC Control Status Register 0 */ | ||
13 | #define ISC_CTRLSR 0x00000008 | ||
14 | |||
15 | #define ISC_CTRL_CAPTURE BIT(0) | ||
16 | #define ISC_CTRL_UPPRO BIT(1) | ||
17 | #define ISC_CTRL_HISREQ BIT(2) | ||
18 | #define ISC_CTRL_HISCLR BIT(3) | ||
19 | |||
20 | /* ISC Parallel Front End Configuration 0 Register */ | ||
21 | #define ISC_PFE_CFG0 0x0000000c | ||
22 | |||
23 | #define ISC_PFE_CFG0_HPOL_LOW BIT(0) | ||
24 | #define ISC_PFE_CFG0_VPOL_LOW BIT(1) | ||
25 | #define ISC_PFE_CFG0_PPOL_LOW BIT(2) | ||
26 | |||
27 | #define ISC_PFE_CFG0_MODE_PROGRESSIVE (0x0 << 4) | ||
28 | #define ISC_PFE_CFG0_MODE_MASK GENMASK(6, 4) | ||
29 | |||
30 | #define ISC_PFE_CFG0_BPS_EIGHT (0x4 << 28) | ||
31 | #define ISC_PFG_CFG0_BPS_NINE (0x3 << 28) | ||
32 | #define ISC_PFG_CFG0_BPS_TEN (0x2 << 28) | ||
33 | #define ISC_PFG_CFG0_BPS_ELEVEN (0x1 << 28) | ||
34 | #define ISC_PFG_CFG0_BPS_TWELVE (0x0 << 28) | ||
35 | #define ISC_PFE_CFG0_BPS_MASK GENMASK(30, 28) | ||
36 | |||
37 | /* ISC Clock Enable Register */ | ||
38 | #define ISC_CLKEN 0x00000018 | ||
39 | |||
40 | /* ISC Clock Disable Register */ | ||
41 | #define ISC_CLKDIS 0x0000001c | ||
42 | |||
43 | /* ISC Clock Status Register */ | ||
44 | #define ISC_CLKSR 0x00000020 | ||
45 | |||
46 | #define ISC_CLK(n) BIT(n) | ||
47 | |||
48 | /* ISC Clock Configuration Register */ | ||
49 | #define ISC_CLKCFG 0x00000024 | ||
50 | #define ISC_CLKCFG_DIV_SHIFT(n) ((n)*16) | ||
51 | #define ISC_CLKCFG_DIV_MASK(n) GENMASK(((n)*16 + 7), (n)*16) | ||
52 | #define ISC_CLKCFG_SEL_SHIFT(n) ((n)*16 + 8) | ||
53 | #define ISC_CLKCFG_SEL_MASK(n) GENMASK(((n)*17 + 8), ((n)*16 + 8)) | ||
54 | |||
55 | /* ISC Interrupt Enable Register */ | ||
56 | #define ISC_INTEN 0x00000028 | ||
57 | |||
58 | /* ISC Interrupt Disable Register */ | ||
59 | #define ISC_INTDIS 0x0000002c | ||
60 | |||
61 | /* ISC Interrupt Mask Register */ | ||
62 | #define ISC_INTMASK 0x00000030 | ||
63 | |||
64 | /* ISC Interrupt Status Register */ | ||
65 | #define ISC_INTSR 0x00000034 | ||
66 | |||
67 | #define ISC_INT_DDONE BIT(8) | ||
68 | |||
69 | /* ISC White Balance Control Register */ | ||
70 | #define ISC_WB_CTRL 0x00000058 | ||
71 | |||
72 | /* ISC White Balance Configuration Register */ | ||
73 | #define ISC_WB_CFG 0x0000005c | ||
74 | |||
75 | /* ISC Color Filter Array Control Register */ | ||
76 | #define ISC_CFA_CTRL 0x00000070 | ||
77 | |||
78 | /* ISC Color Filter Array Configuration Register */ | ||
79 | #define ISC_CFA_CFG 0x00000074 | ||
80 | |||
81 | #define ISC_BAY_CFG_GRGR 0x0 | ||
82 | #define ISC_BAY_CFG_RGRG 0x1 | ||
83 | #define ISC_BAY_CFG_GBGB 0x2 | ||
84 | #define ISC_BAY_CFG_BGBG 0x3 | ||
85 | #define ISC_BAY_CFG_MASK GENMASK(1, 0) | ||
86 | |||
87 | /* ISC Color Correction Control Register */ | ||
88 | #define ISC_CC_CTRL 0x00000078 | ||
89 | |||
90 | /* ISC Gamma Correction Control Register */ | ||
91 | #define ISC_GAM_CTRL 0x00000094 | ||
92 | |||
93 | /* Color Space Conversion Control Register */ | ||
94 | #define ISC_CSC_CTRL 0x00000398 | ||
95 | |||
96 | /* Contrast And Brightness Control Register */ | ||
97 | #define ISC_CBC_CTRL 0x000003b4 | ||
98 | |||
99 | /* Subsampling 4:4:4 to 4:2:2 Control Register */ | ||
100 | #define ISC_SUB422_CTRL 0x000003c4 | ||
101 | |||
102 | /* Subsampling 4:2:2 to 4:2:0 Control Register */ | ||
103 | #define ISC_SUB420_CTRL 0x000003cc | ||
104 | |||
105 | /* Rounding, Limiting and Packing Configuration Register */ | ||
106 | #define ISC_RLP_CFG 0x000003d0 | ||
107 | |||
108 | #define ISC_RLP_CFG_MODE_DAT8 0x0 | ||
109 | #define ISC_RLP_CFG_MODE_DAT9 0x1 | ||
110 | #define ISC_RLP_CFG_MODE_DAT10 0x2 | ||
111 | #define ISC_RLP_CFG_MODE_DAT11 0x3 | ||
112 | #define ISC_RLP_CFG_MODE_DAT12 0x4 | ||
113 | #define ISC_RLP_CFG_MODE_DATY8 0x5 | ||
114 | #define ISC_RLP_CFG_MODE_DATY10 0x6 | ||
115 | #define ISC_RLP_CFG_MODE_ARGB444 0x7 | ||
116 | #define ISC_RLP_CFG_MODE_ARGB555 0x8 | ||
117 | #define ISC_RLP_CFG_MODE_RGB565 0x9 | ||
118 | #define ISC_RLP_CFG_MODE_ARGB32 0xa | ||
119 | #define ISC_RLP_CFG_MODE_YYCC 0xb | ||
120 | #define ISC_RLP_CFG_MODE_YYCC_LIMITED 0xc | ||
121 | #define ISC_RLP_CFG_MODE_MASK GENMASK(3, 0) | ||
122 | |||
123 | /* DMA Configuration Register */ | ||
124 | #define ISC_DCFG 0x000003e0 | ||
125 | #define ISC_DCFG_IMODE_PACKED8 0x0 | ||
126 | #define ISC_DCFG_IMODE_PACKED16 0x1 | ||
127 | #define ISC_DCFG_IMODE_PACKED32 0x2 | ||
128 | #define ISC_DCFG_IMODE_YC422SP 0x3 | ||
129 | #define ISC_DCFG_IMODE_YC422P 0x4 | ||
130 | #define ISC_DCFG_IMODE_YC420SP 0x5 | ||
131 | #define ISC_DCFG_IMODE_YC420P 0x6 | ||
132 | #define ISC_DCFG_IMODE_MASK GENMASK(2, 0) | ||
133 | |||
134 | #define ISC_DCFG_YMBSIZE_SINGLE (0x0 << 4) | ||
135 | #define ISC_DCFG_YMBSIZE_BEATS4 (0x1 << 4) | ||
136 | #define ISC_DCFG_YMBSIZE_BEATS8 (0x2 << 4) | ||
137 | #define ISC_DCFG_YMBSIZE_BEATS16 (0x3 << 4) | ||
138 | #define ISC_DCFG_YMBSIZE_MASK GENMASK(5, 4) | ||
139 | |||
140 | #define ISC_DCFG_CMBSIZE_SINGLE (0x0 << 8) | ||
141 | #define ISC_DCFG_CMBSIZE_BEATS4 (0x1 << 8) | ||
142 | #define ISC_DCFG_CMBSIZE_BEATS8 (0x2 << 8) | ||
143 | #define ISC_DCFG_CMBSIZE_BEATS16 (0x3 << 8) | ||
144 | #define ISC_DCFG_CMBSIZE_MASK GENMASK(9, 8) | ||
145 | |||
146 | /* DMA Control Register */ | ||
147 | #define ISC_DCTRL 0x000003e4 | ||
148 | |||
149 | #define ISC_DCTRL_DVIEW_PACKED (0x0 << 1) | ||
150 | #define ISC_DCTRL_DVIEW_SEMIPLANAR (0x1 << 1) | ||
151 | #define ISC_DCTRL_DVIEW_PLANAR (0x2 << 1) | ||
152 | #define ISC_DCTRL_DVIEW_MASK GENMASK(2, 1) | ||
153 | |||
154 | #define ISC_DCTRL_IE_IS (0x0 << 4) | ||
155 | |||
156 | /* DMA Descriptor Address Register */ | ||
157 | #define ISC_DNDA 0x000003e8 | ||
158 | |||
159 | /* DMA Address 0 Register */ | ||
160 | #define ISC_DAD0 0x000003ec | ||
161 | |||
162 | /* DMA Stride 0 Register */ | ||
163 | #define ISC_DST0 0x000003f0 | ||
164 | |||
165 | #endif | ||
diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c new file mode 100644 index 000000000000..ccfe13b7d3f8 --- /dev/null +++ b/drivers/media/platform/atmel/atmel-isc.c | |||
@@ -0,0 +1,1520 @@ | |||
1 | /* | ||
2 | * Atmel Image Sensor Controller (ISC) driver | ||
3 | * | ||
4 | * Copyright (C) 2016 Atmel | ||
5 | * | ||
6 | * Author: Songjun Wu <songjun.wu@microchip.com> | ||
7 | * | ||
8 | * This program is free software; you may redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA | ||
13 | * | ||
14 | * ISC video pipeline integrates the following submodules: | ||
15 | * PFE: Parallel Front End to sample the camera sensor input stream | ||
16 | * WB: Programmable white balance in the Bayer domain | ||
17 | * CFA: Color filter array interpolation module | ||
18 | * CC: Programmable color correction | ||
19 | * GAM: Gamma correction | ||
20 | * CSC: Programmable color space conversion | ||
21 | * CBC: Contrast and Brightness control | ||
22 | * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling | ||
23 | * RLP: This module performs rounding, range limiting | ||
24 | * and packing of the incoming data | ||
25 | */ | ||
26 | |||
27 | #include <linux/clk.h> | ||
28 | #include <linux/clkdev.h> | ||
29 | #include <linux/clk-provider.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/of.h> | ||
34 | #include <linux/platform_device.h> | ||
35 | #include <linux/pm_runtime.h> | ||
36 | #include <linux/regmap.h> | ||
37 | #include <linux/videodev2.h> | ||
38 | |||
39 | #include <media/v4l2-device.h> | ||
40 | #include <media/v4l2-image-sizes.h> | ||
41 | #include <media/v4l2-ioctl.h> | ||
42 | #include <media/v4l2-of.h> | ||
43 | #include <media/v4l2-subdev.h> | ||
44 | #include <media/videobuf2-dma-contig.h> | ||
45 | |||
46 | #include "atmel-isc-regs.h" | ||
47 | |||
48 | #define ATMEL_ISC_NAME "atmel_isc" | ||
49 | |||
50 | #define ISC_MAX_SUPPORT_WIDTH 2592 | ||
51 | #define ISC_MAX_SUPPORT_HEIGHT 1944 | ||
52 | |||
53 | #define ISC_CLK_MAX_DIV 255 | ||
54 | |||
55 | enum isc_clk_id { | ||
56 | ISC_ISPCK = 0, | ||
57 | ISC_MCK = 1, | ||
58 | }; | ||
59 | |||
60 | struct isc_clk { | ||
61 | struct clk_hw hw; | ||
62 | struct clk *clk; | ||
63 | struct regmap *regmap; | ||
64 | u8 id; | ||
65 | u8 parent_id; | ||
66 | u32 div; | ||
67 | struct device *dev; | ||
68 | }; | ||
69 | |||
70 | #define to_isc_clk(hw) container_of(hw, struct isc_clk, hw) | ||
71 | |||
72 | struct isc_buffer { | ||
73 | struct vb2_v4l2_buffer vb; | ||
74 | struct list_head list; | ||
75 | }; | ||
76 | |||
77 | struct isc_subdev_entity { | ||
78 | struct v4l2_subdev *sd; | ||
79 | struct v4l2_async_subdev *asd; | ||
80 | struct v4l2_async_notifier notifier; | ||
81 | struct v4l2_subdev_pad_config *config; | ||
82 | |||
83 | u32 pfe_cfg0; | ||
84 | |||
85 | struct list_head list; | ||
86 | }; | ||
87 | |||
88 | /* | ||
89 | * struct isc_format - ISC media bus format information | ||
90 | * @fourcc: Fourcc code for this format | ||
91 | * @mbus_code: V4L2 media bus format code. | ||
92 | * @bpp: Bytes per pixel (when stored in memory) | ||
93 | * @reg_bps: reg value for bits per sample | ||
94 | * (when transferred over a bus) | ||
95 | * @support: Indicates format supported by subdev | ||
96 | */ | ||
97 | struct isc_format { | ||
98 | u32 fourcc; | ||
99 | u32 mbus_code; | ||
100 | u8 bpp; | ||
101 | |||
102 | u32 reg_bps; | ||
103 | u32 reg_rlp_mode; | ||
104 | u32 reg_dcfg_imode; | ||
105 | u32 reg_dctrl_dview; | ||
106 | |||
107 | bool support; | ||
108 | }; | ||
109 | |||
110 | #define ISC_PIPE_LINE_NODE_NUM 11 | ||
111 | |||
112 | struct isc_device { | ||
113 | struct regmap *regmap; | ||
114 | struct clk *hclock; | ||
115 | struct clk *ispck; | ||
116 | struct isc_clk isc_clks[2]; | ||
117 | |||
118 | struct device *dev; | ||
119 | struct v4l2_device v4l2_dev; | ||
120 | struct video_device video_dev; | ||
121 | |||
122 | struct vb2_queue vb2_vidq; | ||
123 | spinlock_t dma_queue_lock; | ||
124 | struct list_head dma_queue; | ||
125 | struct isc_buffer *cur_frm; | ||
126 | unsigned int sequence; | ||
127 | bool stop; | ||
128 | struct completion comp; | ||
129 | |||
130 | struct v4l2_format fmt; | ||
131 | struct isc_format **user_formats; | ||
132 | unsigned int num_user_formats; | ||
133 | const struct isc_format *current_fmt; | ||
134 | |||
135 | struct mutex lock; | ||
136 | |||
137 | struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM]; | ||
138 | |||
139 | struct isc_subdev_entity *current_subdev; | ||
140 | struct list_head subdev_entities; | ||
141 | }; | ||
142 | |||
143 | static struct isc_format isc_formats[] = { | ||
144 | { V4L2_PIX_FMT_SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8, | ||
145 | 1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, | ||
146 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, | ||
147 | { V4L2_PIX_FMT_SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8, | ||
148 | 1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, | ||
149 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, | ||
150 | { V4L2_PIX_FMT_SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8, | ||
151 | 1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, | ||
152 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, | ||
153 | { V4L2_PIX_FMT_SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8, | ||
154 | 1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, | ||
155 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, | ||
156 | |||
157 | { V4L2_PIX_FMT_SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10, | ||
158 | 2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10, | ||
159 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | ||
160 | { V4L2_PIX_FMT_SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10, | ||
161 | 2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10, | ||
162 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | ||
163 | { V4L2_PIX_FMT_SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10, | ||
164 | 2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10, | ||
165 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | ||
166 | { V4L2_PIX_FMT_SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10, | ||
167 | 2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10, | ||
168 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | ||
169 | |||
170 | { V4L2_PIX_FMT_SBGGR12, MEDIA_BUS_FMT_SBGGR12_1X12, | ||
171 | 2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12, | ||
172 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | ||
173 | { V4L2_PIX_FMT_SGBRG12, MEDIA_BUS_FMT_SGBRG12_1X12, | ||
174 | 2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12, | ||
175 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | ||
176 | { V4L2_PIX_FMT_SGRBG12, MEDIA_BUS_FMT_SGRBG12_1X12, | ||
177 | 2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12, | ||
178 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | ||
179 | { V4L2_PIX_FMT_SRGGB12, MEDIA_BUS_FMT_SRGGB12_1X12, | ||
180 | 2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12, | ||
181 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | ||
182 | |||
183 | { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_YUYV8_2X8, | ||
184 | 2, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, | ||
185 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, | ||
186 | }; | ||
187 | |||
188 | static int isc_clk_enable(struct clk_hw *hw) | ||
189 | { | ||
190 | struct isc_clk *isc_clk = to_isc_clk(hw); | ||
191 | u32 id = isc_clk->id; | ||
192 | struct regmap *regmap = isc_clk->regmap; | ||
193 | |||
194 | dev_dbg(isc_clk->dev, "ISC CLK: %s, div = %d, parent id = %d\n", | ||
195 | __func__, isc_clk->div, isc_clk->parent_id); | ||
196 | |||
197 | regmap_update_bits(regmap, ISC_CLKCFG, | ||
198 | ISC_CLKCFG_DIV_MASK(id) | ISC_CLKCFG_SEL_MASK(id), | ||
199 | (isc_clk->div << ISC_CLKCFG_DIV_SHIFT(id)) | | ||
200 | (isc_clk->parent_id << ISC_CLKCFG_SEL_SHIFT(id))); | ||
201 | |||
202 | regmap_write(regmap, ISC_CLKEN, ISC_CLK(id)); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static void isc_clk_disable(struct clk_hw *hw) | ||
208 | { | ||
209 | struct isc_clk *isc_clk = to_isc_clk(hw); | ||
210 | u32 id = isc_clk->id; | ||
211 | |||
212 | regmap_write(isc_clk->regmap, ISC_CLKDIS, ISC_CLK(id)); | ||
213 | } | ||
214 | |||
215 | static int isc_clk_is_enabled(struct clk_hw *hw) | ||
216 | { | ||
217 | struct isc_clk *isc_clk = to_isc_clk(hw); | ||
218 | u32 status; | ||
219 | |||
220 | regmap_read(isc_clk->regmap, ISC_CLKSR, &status); | ||
221 | |||
222 | return status & ISC_CLK(isc_clk->id) ? 1 : 0; | ||
223 | } | ||
224 | |||
225 | static unsigned long | ||
226 | isc_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | ||
227 | { | ||
228 | struct isc_clk *isc_clk = to_isc_clk(hw); | ||
229 | |||
230 | return DIV_ROUND_CLOSEST(parent_rate, isc_clk->div + 1); | ||
231 | } | ||
232 | |||
233 | static int isc_clk_determine_rate(struct clk_hw *hw, | ||
234 | struct clk_rate_request *req) | ||
235 | { | ||
236 | struct isc_clk *isc_clk = to_isc_clk(hw); | ||
237 | long best_rate = -EINVAL; | ||
238 | int best_diff = -1; | ||
239 | unsigned int i, div; | ||
240 | |||
241 | for (i = 0; i < clk_hw_get_num_parents(hw); i++) { | ||
242 | struct clk_hw *parent; | ||
243 | unsigned long parent_rate; | ||
244 | |||
245 | parent = clk_hw_get_parent_by_index(hw, i); | ||
246 | if (!parent) | ||
247 | continue; | ||
248 | |||
249 | parent_rate = clk_hw_get_rate(parent); | ||
250 | if (!parent_rate) | ||
251 | continue; | ||
252 | |||
253 | for (div = 1; div < ISC_CLK_MAX_DIV + 2; div++) { | ||
254 | unsigned long rate; | ||
255 | int diff; | ||
256 | |||
257 | rate = DIV_ROUND_CLOSEST(parent_rate, div); | ||
258 | diff = abs(req->rate - rate); | ||
259 | |||
260 | if (best_diff < 0 || best_diff > diff) { | ||
261 | best_rate = rate; | ||
262 | best_diff = diff; | ||
263 | req->best_parent_rate = parent_rate; | ||
264 | req->best_parent_hw = parent; | ||
265 | } | ||
266 | |||
267 | if (!best_diff || rate < req->rate) | ||
268 | break; | ||
269 | } | ||
270 | |||
271 | if (!best_diff) | ||
272 | break; | ||
273 | } | ||
274 | |||
275 | dev_dbg(isc_clk->dev, | ||
276 | "ISC CLK: %s, best_rate = %ld, parent clk: %s @ %ld\n", | ||
277 | __func__, best_rate, | ||
278 | __clk_get_name((req->best_parent_hw)->clk), | ||
279 | req->best_parent_rate); | ||
280 | |||
281 | if (best_rate < 0) | ||
282 | return best_rate; | ||
283 | |||
284 | req->rate = best_rate; | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static int isc_clk_set_parent(struct clk_hw *hw, u8 index) | ||
290 | { | ||
291 | struct isc_clk *isc_clk = to_isc_clk(hw); | ||
292 | |||
293 | if (index >= clk_hw_get_num_parents(hw)) | ||
294 | return -EINVAL; | ||
295 | |||
296 | isc_clk->parent_id = index; | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static u8 isc_clk_get_parent(struct clk_hw *hw) | ||
302 | { | ||
303 | struct isc_clk *isc_clk = to_isc_clk(hw); | ||
304 | |||
305 | return isc_clk->parent_id; | ||
306 | } | ||
307 | |||
308 | static int isc_clk_set_rate(struct clk_hw *hw, | ||
309 | unsigned long rate, | ||
310 | unsigned long parent_rate) | ||
311 | { | ||
312 | struct isc_clk *isc_clk = to_isc_clk(hw); | ||
313 | u32 div; | ||
314 | |||
315 | if (!rate) | ||
316 | return -EINVAL; | ||
317 | |||
318 | div = DIV_ROUND_CLOSEST(parent_rate, rate); | ||
319 | if (div > (ISC_CLK_MAX_DIV + 1) || !div) | ||
320 | return -EINVAL; | ||
321 | |||
322 | isc_clk->div = div - 1; | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static const struct clk_ops isc_clk_ops = { | ||
328 | .enable = isc_clk_enable, | ||
329 | .disable = isc_clk_disable, | ||
330 | .is_enabled = isc_clk_is_enabled, | ||
331 | .recalc_rate = isc_clk_recalc_rate, | ||
332 | .determine_rate = isc_clk_determine_rate, | ||
333 | .set_parent = isc_clk_set_parent, | ||
334 | .get_parent = isc_clk_get_parent, | ||
335 | .set_rate = isc_clk_set_rate, | ||
336 | }; | ||
337 | |||
338 | static int isc_clk_register(struct isc_device *isc, unsigned int id) | ||
339 | { | ||
340 | struct regmap *regmap = isc->regmap; | ||
341 | struct device_node *np = isc->dev->of_node; | ||
342 | struct isc_clk *isc_clk; | ||
343 | struct clk_init_data init; | ||
344 | const char *clk_name = np->name; | ||
345 | const char *parent_names[3]; | ||
346 | int num_parents; | ||
347 | |||
348 | num_parents = of_clk_get_parent_count(np); | ||
349 | if (num_parents < 1 || num_parents > 3) | ||
350 | return -EINVAL; | ||
351 | |||
352 | if (num_parents > 2 && id == ISC_ISPCK) | ||
353 | num_parents = 2; | ||
354 | |||
355 | of_clk_parent_fill(np, parent_names, num_parents); | ||
356 | |||
357 | if (id == ISC_MCK) | ||
358 | of_property_read_string(np, "clock-output-names", &clk_name); | ||
359 | else | ||
360 | clk_name = "isc-ispck"; | ||
361 | |||
362 | init.parent_names = parent_names; | ||
363 | init.num_parents = num_parents; | ||
364 | init.name = clk_name; | ||
365 | init.ops = &isc_clk_ops; | ||
366 | init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; | ||
367 | |||
368 | isc_clk = &isc->isc_clks[id]; | ||
369 | isc_clk->hw.init = &init; | ||
370 | isc_clk->regmap = regmap; | ||
371 | isc_clk->id = id; | ||
372 | isc_clk->dev = isc->dev; | ||
373 | |||
374 | isc_clk->clk = clk_register(isc->dev, &isc_clk->hw); | ||
375 | if (IS_ERR(isc_clk->clk)) { | ||
376 | dev_err(isc->dev, "%s: clock register fail\n", clk_name); | ||
377 | return PTR_ERR(isc_clk->clk); | ||
378 | } else if (id == ISC_MCK) | ||
379 | of_clk_add_provider(np, of_clk_src_simple_get, isc_clk->clk); | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static int isc_clk_init(struct isc_device *isc) | ||
385 | { | ||
386 | unsigned int i; | ||
387 | int ret; | ||
388 | |||
389 | for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) | ||
390 | isc->isc_clks[i].clk = ERR_PTR(-EINVAL); | ||
391 | |||
392 | for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) { | ||
393 | ret = isc_clk_register(isc, i); | ||
394 | if (ret) | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static void isc_clk_cleanup(struct isc_device *isc) | ||
402 | { | ||
403 | unsigned int i; | ||
404 | |||
405 | of_clk_del_provider(isc->dev->of_node); | ||
406 | |||
407 | for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) { | ||
408 | struct isc_clk *isc_clk = &isc->isc_clks[i]; | ||
409 | |||
410 | if (!IS_ERR(isc_clk->clk)) | ||
411 | clk_unregister(isc_clk->clk); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | static int isc_queue_setup(struct vb2_queue *vq, | ||
416 | unsigned int *nbuffers, unsigned int *nplanes, | ||
417 | unsigned int sizes[], struct device *alloc_devs[]) | ||
418 | { | ||
419 | struct isc_device *isc = vb2_get_drv_priv(vq); | ||
420 | unsigned int size = isc->fmt.fmt.pix.sizeimage; | ||
421 | |||
422 | if (*nplanes) | ||
423 | return sizes[0] < size ? -EINVAL : 0; | ||
424 | |||
425 | *nplanes = 1; | ||
426 | sizes[0] = size; | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | static int isc_buffer_prepare(struct vb2_buffer *vb) | ||
432 | { | ||
433 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
434 | struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue); | ||
435 | unsigned long size = isc->fmt.fmt.pix.sizeimage; | ||
436 | |||
437 | if (vb2_plane_size(vb, 0) < size) { | ||
438 | v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n", | ||
439 | vb2_plane_size(vb, 0), size); | ||
440 | return -EINVAL; | ||
441 | } | ||
442 | |||
443 | vb2_set_plane_payload(vb, 0, size); | ||
444 | |||
445 | vbuf->field = isc->fmt.fmt.pix.field; | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static inline void isc_start_dma(struct regmap *regmap, | ||
451 | struct isc_buffer *frm, u32 dview) | ||
452 | { | ||
453 | dma_addr_t addr; | ||
454 | |||
455 | addr = vb2_dma_contig_plane_dma_addr(&frm->vb.vb2_buf, 0); | ||
456 | |||
457 | regmap_write(regmap, ISC_DCTRL, dview | ISC_DCTRL_IE_IS); | ||
458 | regmap_write(regmap, ISC_DAD0, addr); | ||
459 | regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); | ||
460 | } | ||
461 | |||
462 | static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) | ||
463 | { | ||
464 | u32 val; | ||
465 | unsigned int i; | ||
466 | |||
467 | for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { | ||
468 | val = pipeline & BIT(i) ? 1 : 0; | ||
469 | regmap_field_write(isc->pipeline[i], val); | ||
470 | } | ||
471 | } | ||
472 | |||
473 | static int isc_configure(struct isc_device *isc) | ||
474 | { | ||
475 | struct regmap *regmap = isc->regmap; | ||
476 | const struct isc_format *current_fmt = isc->current_fmt; | ||
477 | struct isc_subdev_entity *subdev = isc->current_subdev; | ||
478 | u32 val, mask; | ||
479 | int counter = 10; | ||
480 | |||
481 | val = current_fmt->reg_bps | subdev->pfe_cfg0 | | ||
482 | ISC_PFE_CFG0_MODE_PROGRESSIVE; | ||
483 | mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW | | ||
484 | ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW | | ||
485 | ISC_PFE_CFG0_MODE_MASK; | ||
486 | |||
487 | regmap_update_bits(regmap, ISC_PFE_CFG0, mask, val); | ||
488 | |||
489 | regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK, | ||
490 | current_fmt->reg_rlp_mode); | ||
491 | |||
492 | regmap_update_bits(regmap, ISC_DCFG, ISC_DCFG_IMODE_MASK, | ||
493 | current_fmt->reg_dcfg_imode); | ||
494 | |||
495 | /* Disable the pipeline */ | ||
496 | isc_set_pipeline(isc, 0x0); | ||
497 | |||
498 | /* Update profile */ | ||
499 | regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO); | ||
500 | |||
501 | regmap_read(regmap, ISC_CTRLSR, &val); | ||
502 | while ((val & ISC_CTRL_UPPRO) && counter--) { | ||
503 | usleep_range(1000, 2000); | ||
504 | regmap_read(regmap, ISC_CTRLSR, &val); | ||
505 | } | ||
506 | |||
507 | if (counter < 0) | ||
508 | return -ETIMEDOUT; | ||
509 | |||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
514 | { | ||
515 | struct isc_device *isc = vb2_get_drv_priv(vq); | ||
516 | struct regmap *regmap = isc->regmap; | ||
517 | struct isc_buffer *buf; | ||
518 | unsigned long flags; | ||
519 | int ret; | ||
520 | u32 val; | ||
521 | |||
522 | /* Enable stream on the sub device */ | ||
523 | ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); | ||
524 | if (ret && ret != -ENOIOCTLCMD) { | ||
525 | v4l2_err(&isc->v4l2_dev, "stream on failed in subdev\n"); | ||
526 | goto err_start_stream; | ||
527 | } | ||
528 | |||
529 | pm_runtime_get_sync(isc->dev); | ||
530 | |||
531 | /* Disable all the interrupts */ | ||
532 | regmap_write(isc->regmap, ISC_INTDIS, (u32)~0UL); | ||
533 | |||
534 | /* Clean the interrupt status register */ | ||
535 | regmap_read(regmap, ISC_INTSR, &val); | ||
536 | |||
537 | ret = isc_configure(isc); | ||
538 | if (unlikely(ret)) | ||
539 | goto err_configure; | ||
540 | |||
541 | /* Enable DMA interrupt */ | ||
542 | regmap_write(regmap, ISC_INTEN, ISC_INT_DDONE); | ||
543 | |||
544 | spin_lock_irqsave(&isc->dma_queue_lock, flags); | ||
545 | |||
546 | isc->sequence = 0; | ||
547 | isc->stop = false; | ||
548 | reinit_completion(&isc->comp); | ||
549 | |||
550 | isc->cur_frm = list_first_entry(&isc->dma_queue, | ||
551 | struct isc_buffer, list); | ||
552 | list_del(&isc->cur_frm->list); | ||
553 | |||
554 | isc_start_dma(regmap, isc->cur_frm, isc->current_fmt->reg_dctrl_dview); | ||
555 | |||
556 | spin_unlock_irqrestore(&isc->dma_queue_lock, flags); | ||
557 | |||
558 | return 0; | ||
559 | |||
560 | err_configure: | ||
561 | pm_runtime_put_sync(isc->dev); | ||
562 | |||
563 | v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); | ||
564 | |||
565 | err_start_stream: | ||
566 | spin_lock_irqsave(&isc->dma_queue_lock, flags); | ||
567 | list_for_each_entry(buf, &isc->dma_queue, list) | ||
568 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); | ||
569 | INIT_LIST_HEAD(&isc->dma_queue); | ||
570 | spin_unlock_irqrestore(&isc->dma_queue_lock, flags); | ||
571 | |||
572 | return ret; | ||
573 | } | ||
574 | |||
575 | static void isc_stop_streaming(struct vb2_queue *vq) | ||
576 | { | ||
577 | struct isc_device *isc = vb2_get_drv_priv(vq); | ||
578 | unsigned long flags; | ||
579 | struct isc_buffer *buf; | ||
580 | int ret; | ||
581 | |||
582 | isc->stop = true; | ||
583 | |||
584 | /* Wait until the end of the current frame */ | ||
585 | if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ)) | ||
586 | v4l2_err(&isc->v4l2_dev, | ||
587 | "Timeout waiting for end of the capture\n"); | ||
588 | |||
589 | /* Disable DMA interrupt */ | ||
590 | regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE); | ||
591 | |||
592 | pm_runtime_put_sync(isc->dev); | ||
593 | |||
594 | /* Disable stream on the sub device */ | ||
595 | ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); | ||
596 | if (ret && ret != -ENOIOCTLCMD) | ||
597 | v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n"); | ||
598 | |||
599 | /* Release all active buffers */ | ||
600 | spin_lock_irqsave(&isc->dma_queue_lock, flags); | ||
601 | if (unlikely(isc->cur_frm)) { | ||
602 | vb2_buffer_done(&isc->cur_frm->vb.vb2_buf, | ||
603 | VB2_BUF_STATE_ERROR); | ||
604 | isc->cur_frm = NULL; | ||
605 | } | ||
606 | list_for_each_entry(buf, &isc->dma_queue, list) | ||
607 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
608 | INIT_LIST_HEAD(&isc->dma_queue); | ||
609 | spin_unlock_irqrestore(&isc->dma_queue_lock, flags); | ||
610 | } | ||
611 | |||
612 | static void isc_buffer_queue(struct vb2_buffer *vb) | ||
613 | { | ||
614 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
615 | struct isc_buffer *buf = container_of(vbuf, struct isc_buffer, vb); | ||
616 | struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue); | ||
617 | unsigned long flags; | ||
618 | |||
619 | spin_lock_irqsave(&isc->dma_queue_lock, flags); | ||
620 | list_add_tail(&buf->list, &isc->dma_queue); | ||
621 | spin_unlock_irqrestore(&isc->dma_queue_lock, flags); | ||
622 | } | ||
623 | |||
624 | static struct vb2_ops isc_vb2_ops = { | ||
625 | .queue_setup = isc_queue_setup, | ||
626 | .wait_prepare = vb2_ops_wait_prepare, | ||
627 | .wait_finish = vb2_ops_wait_finish, | ||
628 | .buf_prepare = isc_buffer_prepare, | ||
629 | .start_streaming = isc_start_streaming, | ||
630 | .stop_streaming = isc_stop_streaming, | ||
631 | .buf_queue = isc_buffer_queue, | ||
632 | }; | ||
633 | |||
634 | static int isc_querycap(struct file *file, void *priv, | ||
635 | struct v4l2_capability *cap) | ||
636 | { | ||
637 | struct isc_device *isc = video_drvdata(file); | ||
638 | |||
639 | strcpy(cap->driver, ATMEL_ISC_NAME); | ||
640 | strcpy(cap->card, "Atmel Image Sensor Controller"); | ||
641 | snprintf(cap->bus_info, sizeof(cap->bus_info), | ||
642 | "platform:%s", isc->v4l2_dev.name); | ||
643 | |||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int isc_enum_fmt_vid_cap(struct file *file, void *priv, | ||
648 | struct v4l2_fmtdesc *f) | ||
649 | { | ||
650 | struct isc_device *isc = video_drvdata(file); | ||
651 | u32 index = f->index; | ||
652 | |||
653 | if (index >= isc->num_user_formats) | ||
654 | return -EINVAL; | ||
655 | |||
656 | f->pixelformat = isc->user_formats[index]->fourcc; | ||
657 | |||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | static int isc_g_fmt_vid_cap(struct file *file, void *priv, | ||
662 | struct v4l2_format *fmt) | ||
663 | { | ||
664 | struct isc_device *isc = video_drvdata(file); | ||
665 | |||
666 | *fmt = isc->fmt; | ||
667 | |||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static struct isc_format *find_format_by_fourcc(struct isc_device *isc, | ||
672 | unsigned int fourcc) | ||
673 | { | ||
674 | unsigned int num_formats = isc->num_user_formats; | ||
675 | struct isc_format *fmt; | ||
676 | unsigned int i; | ||
677 | |||
678 | for (i = 0; i < num_formats; i++) { | ||
679 | fmt = isc->user_formats[i]; | ||
680 | if (fmt->fourcc == fourcc) | ||
681 | return fmt; | ||
682 | } | ||
683 | |||
684 | return NULL; | ||
685 | } | ||
686 | |||
687 | static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, | ||
688 | struct isc_format **current_fmt) | ||
689 | { | ||
690 | struct isc_format *isc_fmt; | ||
691 | struct v4l2_pix_format *pixfmt = &f->fmt.pix; | ||
692 | struct v4l2_subdev_format format = { | ||
693 | .which = V4L2_SUBDEV_FORMAT_TRY, | ||
694 | }; | ||
695 | int ret; | ||
696 | |||
697 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
698 | return -EINVAL; | ||
699 | |||
700 | isc_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat); | ||
701 | if (!isc_fmt) { | ||
702 | v4l2_warn(&isc->v4l2_dev, "Format 0x%x not found\n", | ||
703 | pixfmt->pixelformat); | ||
704 | isc_fmt = isc->user_formats[isc->num_user_formats - 1]; | ||
705 | pixfmt->pixelformat = isc_fmt->fourcc; | ||
706 | } | ||
707 | |||
708 | /* Limit to Atmel ISC hardware capabilities */ | ||
709 | if (pixfmt->width > ISC_MAX_SUPPORT_WIDTH) | ||
710 | pixfmt->width = ISC_MAX_SUPPORT_WIDTH; | ||
711 | if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT) | ||
712 | pixfmt->height = ISC_MAX_SUPPORT_HEIGHT; | ||
713 | |||
714 | v4l2_fill_mbus_format(&format.format, pixfmt, isc_fmt->mbus_code); | ||
715 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, | ||
716 | isc->current_subdev->config, &format); | ||
717 | if (ret < 0) | ||
718 | return ret; | ||
719 | |||
720 | v4l2_fill_pix_format(pixfmt, &format.format); | ||
721 | |||
722 | pixfmt->field = V4L2_FIELD_NONE; | ||
723 | pixfmt->bytesperline = pixfmt->width * isc_fmt->bpp; | ||
724 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; | ||
725 | |||
726 | if (current_fmt) | ||
727 | *current_fmt = isc_fmt; | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) | ||
733 | { | ||
734 | struct v4l2_subdev_format format = { | ||
735 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
736 | }; | ||
737 | struct isc_format *current_fmt; | ||
738 | int ret; | ||
739 | |||
740 | ret = isc_try_fmt(isc, f, ¤t_fmt); | ||
741 | if (ret) | ||
742 | return ret; | ||
743 | |||
744 | v4l2_fill_mbus_format(&format.format, &f->fmt.pix, | ||
745 | current_fmt->mbus_code); | ||
746 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, | ||
747 | set_fmt, NULL, &format); | ||
748 | if (ret < 0) | ||
749 | return ret; | ||
750 | |||
751 | isc->fmt = *f; | ||
752 | isc->current_fmt = current_fmt; | ||
753 | |||
754 | return 0; | ||
755 | } | ||
756 | |||
757 | static int isc_s_fmt_vid_cap(struct file *file, void *priv, | ||
758 | struct v4l2_format *f) | ||
759 | { | ||
760 | struct isc_device *isc = video_drvdata(file); | ||
761 | |||
762 | if (vb2_is_streaming(&isc->vb2_vidq)) | ||
763 | return -EBUSY; | ||
764 | |||
765 | return isc_set_fmt(isc, f); | ||
766 | } | ||
767 | |||
768 | static int isc_try_fmt_vid_cap(struct file *file, void *priv, | ||
769 | struct v4l2_format *f) | ||
770 | { | ||
771 | struct isc_device *isc = video_drvdata(file); | ||
772 | |||
773 | return isc_try_fmt(isc, f, NULL); | ||
774 | } | ||
775 | |||
776 | static int isc_enum_input(struct file *file, void *priv, | ||
777 | struct v4l2_input *inp) | ||
778 | { | ||
779 | if (inp->index != 0) | ||
780 | return -EINVAL; | ||
781 | |||
782 | inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
783 | inp->std = 0; | ||
784 | strcpy(inp->name, "Camera"); | ||
785 | |||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | static int isc_g_input(struct file *file, void *priv, unsigned int *i) | ||
790 | { | ||
791 | *i = 0; | ||
792 | |||
793 | return 0; | ||
794 | } | ||
795 | |||
796 | static int isc_s_input(struct file *file, void *priv, unsigned int i) | ||
797 | { | ||
798 | if (i > 0) | ||
799 | return -EINVAL; | ||
800 | |||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) | ||
805 | { | ||
806 | struct isc_device *isc = video_drvdata(file); | ||
807 | |||
808 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
809 | return -EINVAL; | ||
810 | |||
811 | return v4l2_subdev_call(isc->current_subdev->sd, video, g_parm, a); | ||
812 | } | ||
813 | |||
814 | static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) | ||
815 | { | ||
816 | struct isc_device *isc = video_drvdata(file); | ||
817 | |||
818 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
819 | return -EINVAL; | ||
820 | |||
821 | return v4l2_subdev_call(isc->current_subdev->sd, video, s_parm, a); | ||
822 | } | ||
823 | |||
824 | static int isc_enum_framesizes(struct file *file, void *fh, | ||
825 | struct v4l2_frmsizeenum *fsize) | ||
826 | { | ||
827 | struct isc_device *isc = video_drvdata(file); | ||
828 | const struct isc_format *isc_fmt; | ||
829 | struct v4l2_subdev_frame_size_enum fse = { | ||
830 | .index = fsize->index, | ||
831 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
832 | }; | ||
833 | int ret; | ||
834 | |||
835 | isc_fmt = find_format_by_fourcc(isc, fsize->pixel_format); | ||
836 | if (!isc_fmt) | ||
837 | return -EINVAL; | ||
838 | |||
839 | fse.code = isc_fmt->mbus_code; | ||
840 | |||
841 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size, | ||
842 | NULL, &fse); | ||
843 | if (ret) | ||
844 | return ret; | ||
845 | |||
846 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
847 | fsize->discrete.width = fse.max_width; | ||
848 | fsize->discrete.height = fse.max_height; | ||
849 | |||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | static int isc_enum_frameintervals(struct file *file, void *fh, | ||
854 | struct v4l2_frmivalenum *fival) | ||
855 | { | ||
856 | struct isc_device *isc = video_drvdata(file); | ||
857 | const struct isc_format *isc_fmt; | ||
858 | struct v4l2_subdev_frame_interval_enum fie = { | ||
859 | .index = fival->index, | ||
860 | .width = fival->width, | ||
861 | .height = fival->height, | ||
862 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
863 | }; | ||
864 | int ret; | ||
865 | |||
866 | isc_fmt = find_format_by_fourcc(isc, fival->pixel_format); | ||
867 | if (!isc_fmt) | ||
868 | return -EINVAL; | ||
869 | |||
870 | fie.code = isc_fmt->mbus_code; | ||
871 | |||
872 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, | ||
873 | enum_frame_interval, NULL, &fie); | ||
874 | if (ret) | ||
875 | return ret; | ||
876 | |||
877 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; | ||
878 | fival->discrete = fie.interval; | ||
879 | |||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | static const struct v4l2_ioctl_ops isc_ioctl_ops = { | ||
884 | .vidioc_querycap = isc_querycap, | ||
885 | .vidioc_enum_fmt_vid_cap = isc_enum_fmt_vid_cap, | ||
886 | .vidioc_g_fmt_vid_cap = isc_g_fmt_vid_cap, | ||
887 | .vidioc_s_fmt_vid_cap = isc_s_fmt_vid_cap, | ||
888 | .vidioc_try_fmt_vid_cap = isc_try_fmt_vid_cap, | ||
889 | |||
890 | .vidioc_enum_input = isc_enum_input, | ||
891 | .vidioc_g_input = isc_g_input, | ||
892 | .vidioc_s_input = isc_s_input, | ||
893 | |||
894 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
895 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
896 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
897 | .vidioc_expbuf = vb2_ioctl_expbuf, | ||
898 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
899 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
900 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | ||
901 | .vidioc_streamon = vb2_ioctl_streamon, | ||
902 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
903 | |||
904 | .vidioc_g_parm = isc_g_parm, | ||
905 | .vidioc_s_parm = isc_s_parm, | ||
906 | .vidioc_enum_framesizes = isc_enum_framesizes, | ||
907 | .vidioc_enum_frameintervals = isc_enum_frameintervals, | ||
908 | }; | ||
909 | |||
910 | static int isc_open(struct file *file) | ||
911 | { | ||
912 | struct isc_device *isc = video_drvdata(file); | ||
913 | struct v4l2_subdev *sd = isc->current_subdev->sd; | ||
914 | int ret; | ||
915 | |||
916 | if (mutex_lock_interruptible(&isc->lock)) | ||
917 | return -ERESTARTSYS; | ||
918 | |||
919 | ret = v4l2_fh_open(file); | ||
920 | if (ret < 0) | ||
921 | goto unlock; | ||
922 | |||
923 | if (!v4l2_fh_is_singular_file(file)) | ||
924 | goto unlock; | ||
925 | |||
926 | ret = v4l2_subdev_call(sd, core, s_power, 1); | ||
927 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
928 | v4l2_fh_release(file); | ||
929 | goto unlock; | ||
930 | } | ||
931 | |||
932 | ret = isc_set_fmt(isc, &isc->fmt); | ||
933 | if (ret) { | ||
934 | v4l2_subdev_call(sd, core, s_power, 0); | ||
935 | v4l2_fh_release(file); | ||
936 | } | ||
937 | |||
938 | unlock: | ||
939 | mutex_unlock(&isc->lock); | ||
940 | return ret; | ||
941 | } | ||
942 | |||
943 | static int isc_release(struct file *file) | ||
944 | { | ||
945 | struct isc_device *isc = video_drvdata(file); | ||
946 | struct v4l2_subdev *sd = isc->current_subdev->sd; | ||
947 | bool fh_singular; | ||
948 | int ret; | ||
949 | |||
950 | mutex_lock(&isc->lock); | ||
951 | |||
952 | fh_singular = v4l2_fh_is_singular_file(file); | ||
953 | |||
954 | ret = _vb2_fop_release(file, NULL); | ||
955 | |||
956 | if (fh_singular) | ||
957 | v4l2_subdev_call(sd, core, s_power, 0); | ||
958 | |||
959 | mutex_unlock(&isc->lock); | ||
960 | |||
961 | return ret; | ||
962 | } | ||
963 | |||
964 | static const struct v4l2_file_operations isc_fops = { | ||
965 | .owner = THIS_MODULE, | ||
966 | .open = isc_open, | ||
967 | .release = isc_release, | ||
968 | .unlocked_ioctl = video_ioctl2, | ||
969 | .read = vb2_fop_read, | ||
970 | .mmap = vb2_fop_mmap, | ||
971 | .poll = vb2_fop_poll, | ||
972 | }; | ||
973 | |||
974 | static irqreturn_t isc_interrupt(int irq, void *dev_id) | ||
975 | { | ||
976 | struct isc_device *isc = (struct isc_device *)dev_id; | ||
977 | struct regmap *regmap = isc->regmap; | ||
978 | u32 isc_intsr, isc_intmask, pending; | ||
979 | irqreturn_t ret = IRQ_NONE; | ||
980 | |||
981 | spin_lock(&isc->dma_queue_lock); | ||
982 | |||
983 | regmap_read(regmap, ISC_INTSR, &isc_intsr); | ||
984 | regmap_read(regmap, ISC_INTMASK, &isc_intmask); | ||
985 | |||
986 | pending = isc_intsr & isc_intmask; | ||
987 | |||
988 | if (likely(pending & ISC_INT_DDONE)) { | ||
989 | if (isc->cur_frm) { | ||
990 | struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb; | ||
991 | struct vb2_buffer *vb = &vbuf->vb2_buf; | ||
992 | |||
993 | vb->timestamp = ktime_get_ns(); | ||
994 | vbuf->sequence = isc->sequence++; | ||
995 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
996 | isc->cur_frm = NULL; | ||
997 | } | ||
998 | |||
999 | if (!list_empty(&isc->dma_queue) && !isc->stop) { | ||
1000 | isc->cur_frm = list_first_entry(&isc->dma_queue, | ||
1001 | struct isc_buffer, list); | ||
1002 | list_del(&isc->cur_frm->list); | ||
1003 | |||
1004 | isc_start_dma(regmap, isc->cur_frm, | ||
1005 | isc->current_fmt->reg_dctrl_dview); | ||
1006 | } | ||
1007 | |||
1008 | if (isc->stop) | ||
1009 | complete(&isc->comp); | ||
1010 | |||
1011 | ret = IRQ_HANDLED; | ||
1012 | } | ||
1013 | |||
1014 | spin_unlock(&isc->dma_queue_lock); | ||
1015 | |||
1016 | return ret; | ||
1017 | } | ||
1018 | |||
1019 | static int isc_async_bound(struct v4l2_async_notifier *notifier, | ||
1020 | struct v4l2_subdev *subdev, | ||
1021 | struct v4l2_async_subdev *asd) | ||
1022 | { | ||
1023 | struct isc_device *isc = container_of(notifier->v4l2_dev, | ||
1024 | struct isc_device, v4l2_dev); | ||
1025 | struct isc_subdev_entity *subdev_entity = | ||
1026 | container_of(notifier, struct isc_subdev_entity, notifier); | ||
1027 | |||
1028 | if (video_is_registered(&isc->video_dev)) { | ||
1029 | v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n"); | ||
1030 | return -EBUSY; | ||
1031 | } | ||
1032 | |||
1033 | subdev_entity->sd = subdev; | ||
1034 | |||
1035 | return 0; | ||
1036 | } | ||
1037 | |||
1038 | static void isc_async_unbind(struct v4l2_async_notifier *notifier, | ||
1039 | struct v4l2_subdev *subdev, | ||
1040 | struct v4l2_async_subdev *asd) | ||
1041 | { | ||
1042 | struct isc_device *isc = container_of(notifier->v4l2_dev, | ||
1043 | struct isc_device, v4l2_dev); | ||
1044 | |||
1045 | video_unregister_device(&isc->video_dev); | ||
1046 | if (isc->current_subdev->config) | ||
1047 | v4l2_subdev_free_pad_config(isc->current_subdev->config); | ||
1048 | } | ||
1049 | |||
1050 | static struct isc_format *find_format_by_code(unsigned int code, int *index) | ||
1051 | { | ||
1052 | struct isc_format *fmt = &isc_formats[0]; | ||
1053 | unsigned int i; | ||
1054 | |||
1055 | for (i = 0; i < ARRAY_SIZE(isc_formats); i++) { | ||
1056 | if (fmt->mbus_code == code) { | ||
1057 | *index = i; | ||
1058 | return fmt; | ||
1059 | } | ||
1060 | |||
1061 | fmt++; | ||
1062 | } | ||
1063 | |||
1064 | return NULL; | ||
1065 | } | ||
1066 | |||
1067 | static int isc_formats_init(struct isc_device *isc) | ||
1068 | { | ||
1069 | struct isc_format *fmt; | ||
1070 | struct v4l2_subdev *subdev = isc->current_subdev->sd; | ||
1071 | int num_fmts = 0, i, j; | ||
1072 | struct v4l2_subdev_mbus_code_enum mbus_code = { | ||
1073 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1074 | }; | ||
1075 | |||
1076 | fmt = &isc_formats[0]; | ||
1077 | for (i = 0; i < ARRAY_SIZE(isc_formats); i++) { | ||
1078 | fmt->support = false; | ||
1079 | fmt++; | ||
1080 | } | ||
1081 | |||
1082 | while (!v4l2_subdev_call(subdev, pad, enum_mbus_code, | ||
1083 | NULL, &mbus_code)) { | ||
1084 | mbus_code.index++; | ||
1085 | fmt = find_format_by_code(mbus_code.code, &i); | ||
1086 | if (!fmt) | ||
1087 | continue; | ||
1088 | |||
1089 | fmt->support = true; | ||
1090 | num_fmts++; | ||
1091 | } | ||
1092 | |||
1093 | if (!num_fmts) | ||
1094 | return -ENXIO; | ||
1095 | |||
1096 | isc->num_user_formats = num_fmts; | ||
1097 | isc->user_formats = devm_kcalloc(isc->dev, | ||
1098 | num_fmts, sizeof(struct isc_format *), | ||
1099 | GFP_KERNEL); | ||
1100 | if (!isc->user_formats) { | ||
1101 | v4l2_err(&isc->v4l2_dev, "could not allocate memory\n"); | ||
1102 | return -ENOMEM; | ||
1103 | } | ||
1104 | |||
1105 | fmt = &isc_formats[0]; | ||
1106 | for (i = 0, j = 0; i < ARRAY_SIZE(isc_formats); i++) { | ||
1107 | if (fmt->support) | ||
1108 | isc->user_formats[j++] = fmt; | ||
1109 | |||
1110 | fmt++; | ||
1111 | } | ||
1112 | |||
1113 | return 0; | ||
1114 | } | ||
1115 | |||
1116 | static int isc_set_default_fmt(struct isc_device *isc) | ||
1117 | { | ||
1118 | struct v4l2_format f = { | ||
1119 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1120 | .fmt.pix = { | ||
1121 | .width = VGA_WIDTH, | ||
1122 | .height = VGA_HEIGHT, | ||
1123 | .field = V4L2_FIELD_NONE, | ||
1124 | .pixelformat = isc->user_formats[0]->fourcc, | ||
1125 | }, | ||
1126 | }; | ||
1127 | int ret; | ||
1128 | |||
1129 | ret = isc_try_fmt(isc, &f, NULL); | ||
1130 | if (ret) | ||
1131 | return ret; | ||
1132 | |||
1133 | isc->current_fmt = isc->user_formats[0]; | ||
1134 | isc->fmt = f; | ||
1135 | |||
1136 | return 0; | ||
1137 | } | ||
1138 | |||
1139 | static int isc_async_complete(struct v4l2_async_notifier *notifier) | ||
1140 | { | ||
1141 | struct isc_device *isc = container_of(notifier->v4l2_dev, | ||
1142 | struct isc_device, v4l2_dev); | ||
1143 | struct isc_subdev_entity *sd_entity; | ||
1144 | struct video_device *vdev = &isc->video_dev; | ||
1145 | struct vb2_queue *q = &isc->vb2_vidq; | ||
1146 | int ret; | ||
1147 | |||
1148 | isc->current_subdev = container_of(notifier, | ||
1149 | struct isc_subdev_entity, notifier); | ||
1150 | sd_entity = isc->current_subdev; | ||
1151 | |||
1152 | mutex_init(&isc->lock); | ||
1153 | init_completion(&isc->comp); | ||
1154 | |||
1155 | /* Initialize videobuf2 queue */ | ||
1156 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1157 | q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; | ||
1158 | q->drv_priv = isc; | ||
1159 | q->buf_struct_size = sizeof(struct isc_buffer); | ||
1160 | q->ops = &isc_vb2_ops; | ||
1161 | q->mem_ops = &vb2_dma_contig_memops; | ||
1162 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
1163 | q->lock = &isc->lock; | ||
1164 | q->min_buffers_needed = 1; | ||
1165 | q->dev = isc->dev; | ||
1166 | |||
1167 | ret = vb2_queue_init(q); | ||
1168 | if (ret < 0) { | ||
1169 | v4l2_err(&isc->v4l2_dev, | ||
1170 | "vb2_queue_init() failed: %d\n", ret); | ||
1171 | return ret; | ||
1172 | } | ||
1173 | |||
1174 | /* Init video dma queues */ | ||
1175 | INIT_LIST_HEAD(&isc->dma_queue); | ||
1176 | spin_lock_init(&isc->dma_queue_lock); | ||
1177 | |||
1178 | sd_entity->config = v4l2_subdev_alloc_pad_config(sd_entity->sd); | ||
1179 | if (sd_entity->config == NULL) | ||
1180 | return -ENOMEM; | ||
1181 | |||
1182 | ret = isc_formats_init(isc); | ||
1183 | if (ret < 0) { | ||
1184 | v4l2_err(&isc->v4l2_dev, | ||
1185 | "Init format failed: %d\n", ret); | ||
1186 | return ret; | ||
1187 | } | ||
1188 | |||
1189 | ret = isc_set_default_fmt(isc); | ||
1190 | if (ret) { | ||
1191 | v4l2_err(&isc->v4l2_dev, "Could not set default format\n"); | ||
1192 | return ret; | ||
1193 | } | ||
1194 | |||
1195 | /* Register video device */ | ||
1196 | strlcpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name)); | ||
1197 | vdev->release = video_device_release_empty; | ||
1198 | vdev->fops = &isc_fops; | ||
1199 | vdev->ioctl_ops = &isc_ioctl_ops; | ||
1200 | vdev->v4l2_dev = &isc->v4l2_dev; | ||
1201 | vdev->vfl_dir = VFL_DIR_RX; | ||
1202 | vdev->queue = q; | ||
1203 | vdev->lock = &isc->lock; | ||
1204 | vdev->ctrl_handler = isc->current_subdev->sd->ctrl_handler; | ||
1205 | vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; | ||
1206 | video_set_drvdata(vdev, isc); | ||
1207 | |||
1208 | ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | ||
1209 | if (ret < 0) { | ||
1210 | v4l2_err(&isc->v4l2_dev, | ||
1211 | "video_register_device failed: %d\n", ret); | ||
1212 | return ret; | ||
1213 | } | ||
1214 | |||
1215 | return 0; | ||
1216 | } | ||
1217 | |||
1218 | static void isc_subdev_cleanup(struct isc_device *isc) | ||
1219 | { | ||
1220 | struct isc_subdev_entity *subdev_entity; | ||
1221 | |||
1222 | list_for_each_entry(subdev_entity, &isc->subdev_entities, list) | ||
1223 | v4l2_async_notifier_unregister(&subdev_entity->notifier); | ||
1224 | |||
1225 | INIT_LIST_HEAD(&isc->subdev_entities); | ||
1226 | } | ||
1227 | |||
1228 | static int isc_pipeline_init(struct isc_device *isc) | ||
1229 | { | ||
1230 | struct device *dev = isc->dev; | ||
1231 | struct regmap *regmap = isc->regmap; | ||
1232 | struct regmap_field *regs; | ||
1233 | unsigned int i; | ||
1234 | |||
1235 | /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */ | ||
1236 | const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = { | ||
1237 | REG_FIELD(ISC_WB_CTRL, 0, 0), | ||
1238 | REG_FIELD(ISC_CFA_CTRL, 0, 0), | ||
1239 | REG_FIELD(ISC_CC_CTRL, 0, 0), | ||
1240 | REG_FIELD(ISC_GAM_CTRL, 0, 0), | ||
1241 | REG_FIELD(ISC_GAM_CTRL, 1, 1), | ||
1242 | REG_FIELD(ISC_GAM_CTRL, 2, 2), | ||
1243 | REG_FIELD(ISC_GAM_CTRL, 3, 3), | ||
1244 | REG_FIELD(ISC_CSC_CTRL, 0, 0), | ||
1245 | REG_FIELD(ISC_CBC_CTRL, 0, 0), | ||
1246 | REG_FIELD(ISC_SUB422_CTRL, 0, 0), | ||
1247 | REG_FIELD(ISC_SUB420_CTRL, 0, 0), | ||
1248 | }; | ||
1249 | |||
1250 | for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { | ||
1251 | regs = devm_regmap_field_alloc(dev, regmap, regfields[i]); | ||
1252 | if (IS_ERR(regs)) | ||
1253 | return PTR_ERR(regs); | ||
1254 | |||
1255 | isc->pipeline[i] = regs; | ||
1256 | } | ||
1257 | |||
1258 | return 0; | ||
1259 | } | ||
1260 | |||
1261 | static int isc_parse_dt(struct device *dev, struct isc_device *isc) | ||
1262 | { | ||
1263 | struct device_node *np = dev->of_node; | ||
1264 | struct device_node *epn = NULL, *rem; | ||
1265 | struct v4l2_of_endpoint v4l2_epn; | ||
1266 | struct isc_subdev_entity *subdev_entity; | ||
1267 | unsigned int flags; | ||
1268 | int ret; | ||
1269 | |||
1270 | INIT_LIST_HEAD(&isc->subdev_entities); | ||
1271 | |||
1272 | for (; ;) { | ||
1273 | epn = of_graph_get_next_endpoint(np, epn); | ||
1274 | if (!epn) | ||
1275 | break; | ||
1276 | |||
1277 | rem = of_graph_get_remote_port_parent(epn); | ||
1278 | if (!rem) { | ||
1279 | dev_notice(dev, "Remote device at %s not found\n", | ||
1280 | of_node_full_name(epn)); | ||
1281 | continue; | ||
1282 | } | ||
1283 | |||
1284 | ret = v4l2_of_parse_endpoint(epn, &v4l2_epn); | ||
1285 | if (ret) { | ||
1286 | of_node_put(rem); | ||
1287 | ret = -EINVAL; | ||
1288 | dev_err(dev, "Could not parse the endpoint\n"); | ||
1289 | break; | ||
1290 | } | ||
1291 | |||
1292 | subdev_entity = devm_kzalloc(dev, | ||
1293 | sizeof(*subdev_entity), GFP_KERNEL); | ||
1294 | if (subdev_entity == NULL) { | ||
1295 | of_node_put(rem); | ||
1296 | ret = -ENOMEM; | ||
1297 | break; | ||
1298 | } | ||
1299 | |||
1300 | subdev_entity->asd = devm_kzalloc(dev, | ||
1301 | sizeof(*subdev_entity->asd), GFP_KERNEL); | ||
1302 | if (subdev_entity->asd == NULL) { | ||
1303 | of_node_put(rem); | ||
1304 | ret = -ENOMEM; | ||
1305 | break; | ||
1306 | } | ||
1307 | |||
1308 | flags = v4l2_epn.bus.parallel.flags; | ||
1309 | |||
1310 | if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
1311 | subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW; | ||
1312 | |||
1313 | if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
1314 | subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW; | ||
1315 | |||
1316 | if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
1317 | subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW; | ||
1318 | |||
1319 | subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_OF; | ||
1320 | subdev_entity->asd->match.of.node = rem; | ||
1321 | list_add_tail(&subdev_entity->list, &isc->subdev_entities); | ||
1322 | } | ||
1323 | |||
1324 | of_node_put(epn); | ||
1325 | return ret; | ||
1326 | } | ||
1327 | |||
1328 | /* regmap configuration */ | ||
1329 | #define ATMEL_ISC_REG_MAX 0xbfc | ||
1330 | static const struct regmap_config isc_regmap_config = { | ||
1331 | .reg_bits = 32, | ||
1332 | .reg_stride = 4, | ||
1333 | .val_bits = 32, | ||
1334 | .max_register = ATMEL_ISC_REG_MAX, | ||
1335 | }; | ||
1336 | |||
1337 | static int atmel_isc_probe(struct platform_device *pdev) | ||
1338 | { | ||
1339 | struct device *dev = &pdev->dev; | ||
1340 | struct isc_device *isc; | ||
1341 | struct resource *res; | ||
1342 | void __iomem *io_base; | ||
1343 | struct isc_subdev_entity *subdev_entity; | ||
1344 | int irq; | ||
1345 | int ret; | ||
1346 | |||
1347 | isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL); | ||
1348 | if (!isc) | ||
1349 | return -ENOMEM; | ||
1350 | |||
1351 | platform_set_drvdata(pdev, isc); | ||
1352 | isc->dev = dev; | ||
1353 | |||
1354 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1355 | io_base = devm_ioremap_resource(dev, res); | ||
1356 | if (IS_ERR(io_base)) | ||
1357 | return PTR_ERR(io_base); | ||
1358 | |||
1359 | isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config); | ||
1360 | if (IS_ERR(isc->regmap)) { | ||
1361 | ret = PTR_ERR(isc->regmap); | ||
1362 | dev_err(dev, "failed to init register map: %d\n", ret); | ||
1363 | return ret; | ||
1364 | } | ||
1365 | |||
1366 | irq = platform_get_irq(pdev, 0); | ||
1367 | if (irq < 0) { | ||
1368 | ret = irq; | ||
1369 | dev_err(dev, "failed to get irq: %d\n", ret); | ||
1370 | return ret; | ||
1371 | } | ||
1372 | |||
1373 | ret = devm_request_irq(dev, irq, isc_interrupt, 0, | ||
1374 | ATMEL_ISC_NAME, isc); | ||
1375 | if (ret < 0) { | ||
1376 | dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n", | ||
1377 | irq, ret); | ||
1378 | return ret; | ||
1379 | } | ||
1380 | |||
1381 | ret = isc_pipeline_init(isc); | ||
1382 | if (ret) | ||
1383 | return ret; | ||
1384 | |||
1385 | isc->hclock = devm_clk_get(dev, "hclock"); | ||
1386 | if (IS_ERR(isc->hclock)) { | ||
1387 | ret = PTR_ERR(isc->hclock); | ||
1388 | dev_err(dev, "failed to get hclock: %d\n", ret); | ||
1389 | return ret; | ||
1390 | } | ||
1391 | |||
1392 | ret = isc_clk_init(isc); | ||
1393 | if (ret) { | ||
1394 | dev_err(dev, "failed to init isc clock: %d\n", ret); | ||
1395 | goto clean_isc_clk; | ||
1396 | } | ||
1397 | |||
1398 | isc->ispck = isc->isc_clks[ISC_ISPCK].clk; | ||
1399 | |||
1400 | /* ispck should be greater or equal to hclock */ | ||
1401 | ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock)); | ||
1402 | if (ret) { | ||
1403 | dev_err(dev, "failed to set ispck rate: %d\n", ret); | ||
1404 | goto clean_isc_clk; | ||
1405 | } | ||
1406 | |||
1407 | ret = v4l2_device_register(dev, &isc->v4l2_dev); | ||
1408 | if (ret) { | ||
1409 | dev_err(dev, "unable to register v4l2 device.\n"); | ||
1410 | goto clean_isc_clk; | ||
1411 | } | ||
1412 | |||
1413 | ret = isc_parse_dt(dev, isc); | ||
1414 | if (ret) { | ||
1415 | dev_err(dev, "fail to parse device tree\n"); | ||
1416 | goto unregister_v4l2_device; | ||
1417 | } | ||
1418 | |||
1419 | if (list_empty(&isc->subdev_entities)) { | ||
1420 | dev_err(dev, "no subdev found\n"); | ||
1421 | goto unregister_v4l2_device; | ||
1422 | } | ||
1423 | |||
1424 | list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { | ||
1425 | subdev_entity->notifier.subdevs = &subdev_entity->asd; | ||
1426 | subdev_entity->notifier.num_subdevs = 1; | ||
1427 | subdev_entity->notifier.bound = isc_async_bound; | ||
1428 | subdev_entity->notifier.unbind = isc_async_unbind; | ||
1429 | subdev_entity->notifier.complete = isc_async_complete; | ||
1430 | |||
1431 | ret = v4l2_async_notifier_register(&isc->v4l2_dev, | ||
1432 | &subdev_entity->notifier); | ||
1433 | if (ret) { | ||
1434 | dev_err(dev, "fail to register async notifier\n"); | ||
1435 | goto cleanup_subdev; | ||
1436 | } | ||
1437 | |||
1438 | if (video_is_registered(&isc->video_dev)) | ||
1439 | break; | ||
1440 | } | ||
1441 | |||
1442 | pm_runtime_enable(dev); | ||
1443 | |||
1444 | return 0; | ||
1445 | |||
1446 | cleanup_subdev: | ||
1447 | isc_subdev_cleanup(isc); | ||
1448 | |||
1449 | unregister_v4l2_device: | ||
1450 | v4l2_device_unregister(&isc->v4l2_dev); | ||
1451 | |||
1452 | clean_isc_clk: | ||
1453 | isc_clk_cleanup(isc); | ||
1454 | |||
1455 | return ret; | ||
1456 | } | ||
1457 | |||
1458 | static int atmel_isc_remove(struct platform_device *pdev) | ||
1459 | { | ||
1460 | struct isc_device *isc = platform_get_drvdata(pdev); | ||
1461 | |||
1462 | pm_runtime_disable(&pdev->dev); | ||
1463 | |||
1464 | isc_subdev_cleanup(isc); | ||
1465 | |||
1466 | v4l2_device_unregister(&isc->v4l2_dev); | ||
1467 | |||
1468 | isc_clk_cleanup(isc); | ||
1469 | |||
1470 | return 0; | ||
1471 | } | ||
1472 | |||
1473 | static int __maybe_unused isc_runtime_suspend(struct device *dev) | ||
1474 | { | ||
1475 | struct isc_device *isc = dev_get_drvdata(dev); | ||
1476 | |||
1477 | clk_disable_unprepare(isc->ispck); | ||
1478 | clk_disable_unprepare(isc->hclock); | ||
1479 | |||
1480 | return 0; | ||
1481 | } | ||
1482 | |||
1483 | static int __maybe_unused isc_runtime_resume(struct device *dev) | ||
1484 | { | ||
1485 | struct isc_device *isc = dev_get_drvdata(dev); | ||
1486 | int ret; | ||
1487 | |||
1488 | ret = clk_prepare_enable(isc->hclock); | ||
1489 | if (ret) | ||
1490 | return ret; | ||
1491 | |||
1492 | return clk_prepare_enable(isc->ispck); | ||
1493 | } | ||
1494 | |||
1495 | static const struct dev_pm_ops atmel_isc_dev_pm_ops = { | ||
1496 | SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL) | ||
1497 | }; | ||
1498 | |||
1499 | static const struct of_device_id atmel_isc_of_match[] = { | ||
1500 | { .compatible = "atmel,sama5d2-isc" }, | ||
1501 | { } | ||
1502 | }; | ||
1503 | MODULE_DEVICE_TABLE(of, atmel_isc_of_match); | ||
1504 | |||
1505 | static struct platform_driver atmel_isc_driver = { | ||
1506 | .probe = atmel_isc_probe, | ||
1507 | .remove = atmel_isc_remove, | ||
1508 | .driver = { | ||
1509 | .name = ATMEL_ISC_NAME, | ||
1510 | .pm = &atmel_isc_dev_pm_ops, | ||
1511 | .of_match_table = of_match_ptr(atmel_isc_of_match), | ||
1512 | }, | ||
1513 | }; | ||
1514 | |||
1515 | module_platform_driver(atmel_isc_driver); | ||
1516 | |||
1517 | MODULE_AUTHOR("Songjun Wu <songjun.wu@microchip.com>"); | ||
1518 | MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC"); | ||
1519 | MODULE_LICENSE("GPL v2"); | ||
1520 | MODULE_SUPPORTED_DEVICE("video"); | ||
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 0b1709e96673..a9bc0175e4d3 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c | |||
@@ -440,7 +440,7 @@ vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, | |||
440 | /* | 440 | /* |
441 | * Application initially set the image format. Current display | 441 | * Application initially set the image format. Current display |
442 | * size is obtained from the vpbe display controller. expected_xsize | 442 | * size is obtained from the vpbe display controller. expected_xsize |
443 | * and expected_ysize are set through S_CROP ioctl. Based on this, | 443 | * and expected_ysize are set through S_SELECTION ioctl. Based on this, |
444 | * driver will calculate the scale factors for vertical and | 444 | * driver will calculate the scale factors for vertical and |
445 | * horizontal direction so that the image is displayed scaled | 445 | * horizontal direction so that the image is displayed scaled |
446 | * and expanded. Application uses expansion to display the image | 446 | * and expanded. Application uses expansion to display the image |
@@ -649,24 +649,23 @@ static int vpbe_display_querycap(struct file *file, void *priv, | |||
649 | return 0; | 649 | return 0; |
650 | } | 650 | } |
651 | 651 | ||
652 | static int vpbe_display_s_crop(struct file *file, void *priv, | 652 | static int vpbe_display_s_selection(struct file *file, void *priv, |
653 | const struct v4l2_crop *crop) | 653 | struct v4l2_selection *sel) |
654 | { | 654 | { |
655 | struct vpbe_layer *layer = video_drvdata(file); | 655 | struct vpbe_layer *layer = video_drvdata(file); |
656 | struct vpbe_display *disp_dev = layer->disp_dev; | 656 | struct vpbe_display *disp_dev = layer->disp_dev; |
657 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | 657 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; |
658 | struct osd_layer_config *cfg = &layer->layer_info.config; | 658 | struct osd_layer_config *cfg = &layer->layer_info.config; |
659 | struct osd_state *osd_device = disp_dev->osd_device; | 659 | struct osd_state *osd_device = disp_dev->osd_device; |
660 | struct v4l2_rect rect = crop->c; | 660 | struct v4l2_rect rect = sel->r; |
661 | int ret; | 661 | int ret; |
662 | 662 | ||
663 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | 663 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, |
664 | "VIDIOC_S_CROP, layer id = %d\n", layer->device_id); | 664 | "VIDIOC_S_SELECTION, layer id = %d\n", layer->device_id); |
665 | 665 | ||
666 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { | 666 | if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || |
667 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); | 667 | sel->target != V4L2_SEL_TGT_CROP) |
668 | return -EINVAL; | 668 | return -EINVAL; |
669 | } | ||
670 | 669 | ||
671 | if (rect.top < 0) | 670 | if (rect.top < 0) |
672 | rect.top = 0; | 671 | rect.top = 0; |
@@ -714,32 +713,45 @@ static int vpbe_display_s_crop(struct file *file, void *priv, | |||
714 | else | 713 | else |
715 | osd_device->ops.set_interpolation_filter(osd_device, 0); | 714 | osd_device->ops.set_interpolation_filter(osd_device, 0); |
716 | 715 | ||
716 | sel->r = rect; | ||
717 | return 0; | 717 | return 0; |
718 | } | 718 | } |
719 | 719 | ||
720 | static int vpbe_display_g_crop(struct file *file, void *priv, | 720 | static int vpbe_display_g_selection(struct file *file, void *priv, |
721 | struct v4l2_crop *crop) | 721 | struct v4l2_selection *sel) |
722 | { | 722 | { |
723 | struct vpbe_layer *layer = video_drvdata(file); | 723 | struct vpbe_layer *layer = video_drvdata(file); |
724 | struct osd_layer_config *cfg = &layer->layer_info.config; | 724 | struct osd_layer_config *cfg = &layer->layer_info.config; |
725 | struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; | 725 | struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; |
726 | struct osd_state *osd_device = layer->disp_dev->osd_device; | 726 | struct osd_state *osd_device = layer->disp_dev->osd_device; |
727 | struct v4l2_rect *rect = &crop->c; | 727 | struct v4l2_rect *rect = &sel->r; |
728 | 728 | ||
729 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | 729 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, |
730 | "VIDIOC_G_CROP, layer id = %d\n", | 730 | "VIDIOC_G_SELECTION, layer id = %d\n", |
731 | layer->device_id); | 731 | layer->device_id); |
732 | 732 | ||
733 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { | 733 | if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) |
734 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); | 734 | return -EINVAL; |
735 | |||
736 | switch (sel->target) { | ||
737 | case V4L2_SEL_TGT_CROP: | ||
738 | osd_device->ops.get_layer_config(osd_device, | ||
739 | layer->layer_info.id, cfg); | ||
740 | rect->top = cfg->ypos; | ||
741 | rect->left = cfg->xpos; | ||
742 | rect->width = cfg->xsize; | ||
743 | rect->height = cfg->ysize; | ||
744 | break; | ||
745 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
746 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
747 | rect->left = 0; | ||
748 | rect->top = 0; | ||
749 | rect->width = vpbe_dev->current_timings.xres; | ||
750 | rect->height = vpbe_dev->current_timings.yres; | ||
751 | break; | ||
752 | default: | ||
735 | return -EINVAL; | 753 | return -EINVAL; |
736 | } | 754 | } |
737 | osd_device->ops.get_layer_config(osd_device, | ||
738 | layer->layer_info.id, cfg); | ||
739 | rect->top = cfg->ypos; | ||
740 | rect->left = cfg->xpos; | ||
741 | rect->width = cfg->xsize; | ||
742 | rect->height = cfg->ysize; | ||
743 | 755 | ||
744 | return 0; | 756 | return 0; |
745 | } | 757 | } |
@@ -752,13 +764,10 @@ static int vpbe_display_cropcap(struct file *file, void *priv, | |||
752 | 764 | ||
753 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n"); | 765 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n"); |
754 | 766 | ||
755 | cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | 767 | if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) |
756 | cropcap->bounds.left = 0; | 768 | return -EINVAL; |
757 | cropcap->bounds.top = 0; | 769 | |
758 | cropcap->bounds.width = vpbe_dev->current_timings.xres; | ||
759 | cropcap->bounds.height = vpbe_dev->current_timings.yres; | ||
760 | cropcap->pixelaspect = vpbe_dev->current_timings.aspect; | 770 | cropcap->pixelaspect = vpbe_dev->current_timings.aspect; |
761 | cropcap->defrect = cropcap->bounds; | ||
762 | return 0; | 771 | return 0; |
763 | } | 772 | } |
764 | 773 | ||
@@ -1251,8 +1260,8 @@ static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { | |||
1251 | .vidioc_expbuf = vb2_ioctl_expbuf, | 1260 | .vidioc_expbuf = vb2_ioctl_expbuf, |
1252 | 1261 | ||
1253 | .vidioc_cropcap = vpbe_display_cropcap, | 1262 | .vidioc_cropcap = vpbe_display_cropcap, |
1254 | .vidioc_g_crop = vpbe_display_g_crop, | 1263 | .vidioc_g_selection = vpbe_display_g_selection, |
1255 | .vidioc_s_crop = vpbe_display_s_crop, | 1264 | .vidioc_s_selection = vpbe_display_s_selection, |
1256 | 1265 | ||
1257 | .vidioc_s_std = vpbe_display_s_std, | 1266 | .vidioc_s_std = vpbe_display_s_std, |
1258 | .vidioc_g_std = vpbe_display_g_std, | 1267 | .vidioc_g_std = vpbe_display_g_std, |
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 7767e072d623..6efb2f1631c4 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c | |||
@@ -1610,38 +1610,53 @@ static int vpfe_cropcap(struct file *file, void *priv, | |||
1610 | 1610 | ||
1611 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n"); | 1611 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n"); |
1612 | 1612 | ||
1613 | if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards)) | 1613 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1614 | return -EINVAL; | 1614 | return -EINVAL; |
1615 | /* If std_index is invalid, then just return (== 1:1 aspect) */ | ||
1616 | if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards)) | ||
1617 | return 0; | ||
1615 | 1618 | ||
1616 | memset(crop, 0, sizeof(struct v4l2_cropcap)); | ||
1617 | crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1618 | crop->bounds.width = crop->defrect.width = | ||
1619 | vpfe_standards[vpfe_dev->std_index].width; | ||
1620 | crop->bounds.height = crop->defrect.height = | ||
1621 | vpfe_standards[vpfe_dev->std_index].height; | ||
1622 | crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect; | 1619 | crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect; |
1623 | return 0; | 1620 | return 0; |
1624 | } | 1621 | } |
1625 | 1622 | ||
1626 | static int vpfe_g_crop(struct file *file, void *priv, | 1623 | static int vpfe_g_selection(struct file *file, void *priv, |
1627 | struct v4l2_crop *crop) | 1624 | struct v4l2_selection *sel) |
1628 | { | 1625 | { |
1629 | struct vpfe_device *vpfe_dev = video_drvdata(file); | 1626 | struct vpfe_device *vpfe_dev = video_drvdata(file); |
1630 | 1627 | ||
1631 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_crop\n"); | 1628 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_selection\n"); |
1632 | 1629 | ||
1633 | crop->c = vpfe_dev->crop; | 1630 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1631 | return -EINVAL; | ||
1632 | |||
1633 | switch (sel->target) { | ||
1634 | case V4L2_SEL_TGT_CROP: | ||
1635 | sel->r = vpfe_dev->crop; | ||
1636 | break; | ||
1637 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
1638 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
1639 | sel->r.width = vpfe_standards[vpfe_dev->std_index].width; | ||
1640 | sel->r.height = vpfe_standards[vpfe_dev->std_index].height; | ||
1641 | break; | ||
1642 | default: | ||
1643 | return -EINVAL; | ||
1644 | } | ||
1634 | return 0; | 1645 | return 0; |
1635 | } | 1646 | } |
1636 | 1647 | ||
1637 | static int vpfe_s_crop(struct file *file, void *priv, | 1648 | static int vpfe_s_selection(struct file *file, void *priv, |
1638 | const struct v4l2_crop *crop) | 1649 | struct v4l2_selection *sel) |
1639 | { | 1650 | { |
1640 | struct vpfe_device *vpfe_dev = video_drvdata(file); | 1651 | struct vpfe_device *vpfe_dev = video_drvdata(file); |
1641 | struct v4l2_rect rect = crop->c; | 1652 | struct v4l2_rect rect = sel->r; |
1642 | int ret = 0; | 1653 | int ret = 0; |
1643 | 1654 | ||
1644 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n"); | 1655 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_selection\n"); |
1656 | |||
1657 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
1658 | sel->target != V4L2_SEL_TGT_CROP) | ||
1659 | return -EINVAL; | ||
1645 | 1660 | ||
1646 | if (vpfe_dev->started) { | 1661 | if (vpfe_dev->started) { |
1647 | /* make sure streaming is not started */ | 1662 | /* make sure streaming is not started */ |
@@ -1669,7 +1684,7 @@ static int vpfe_s_crop(struct file *file, void *priv, | |||
1669 | vpfe_dev->std_info.active_pixels) || | 1684 | vpfe_dev->std_info.active_pixels) || |
1670 | (rect.top + rect.height > | 1685 | (rect.top + rect.height > |
1671 | vpfe_dev->std_info.active_lines)) { | 1686 | vpfe_dev->std_info.active_lines)) { |
1672 | v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n"); | 1687 | v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_SELECTION params\n"); |
1673 | ret = -EINVAL; | 1688 | ret = -EINVAL; |
1674 | goto unlock_out; | 1689 | goto unlock_out; |
1675 | } | 1690 | } |
@@ -1682,6 +1697,7 @@ static int vpfe_s_crop(struct file *file, void *priv, | |||
1682 | vpfe_dev->fmt.fmt.pix.bytesperline * | 1697 | vpfe_dev->fmt.fmt.pix.bytesperline * |
1683 | vpfe_dev->fmt.fmt.pix.height; | 1698 | vpfe_dev->fmt.fmt.pix.height; |
1684 | vpfe_dev->crop = rect; | 1699 | vpfe_dev->crop = rect; |
1700 | sel->r = rect; | ||
1685 | unlock_out: | 1701 | unlock_out: |
1686 | mutex_unlock(&vpfe_dev->lock); | 1702 | mutex_unlock(&vpfe_dev->lock); |
1687 | return ret; | 1703 | return ret; |
@@ -1760,8 +1776,8 @@ static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { | |||
1760 | .vidioc_streamon = vpfe_streamon, | 1776 | .vidioc_streamon = vpfe_streamon, |
1761 | .vidioc_streamoff = vpfe_streamoff, | 1777 | .vidioc_streamoff = vpfe_streamoff, |
1762 | .vidioc_cropcap = vpfe_cropcap, | 1778 | .vidioc_cropcap = vpfe_cropcap, |
1763 | .vidioc_g_crop = vpfe_g_crop, | 1779 | .vidioc_g_selection = vpfe_g_selection, |
1764 | .vidioc_s_crop = vpfe_s_crop, | 1780 | .vidioc_s_selection = vpfe_s_selection, |
1765 | .vidioc_default = vpfe_param_handler, | 1781 | .vidioc_default = vpfe_param_handler, |
1766 | }; | 1782 | }; |
1767 | 1783 | ||
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index ec6494cbdd45..9f03b791b711 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c | |||
@@ -261,7 +261,7 @@ static void gsc_m2m_buf_queue(struct vb2_buffer *vb) | |||
261 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); | 261 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); |
262 | } | 262 | } |
263 | 263 | ||
264 | static struct vb2_ops gsc_m2m_qops = { | 264 | static const struct vb2_ops gsc_m2m_qops = { |
265 | .queue_setup = gsc_m2m_queue_setup, | 265 | .queue_setup = gsc_m2m_queue_setup, |
266 | .buf_prepare = gsc_m2m_buf_prepare, | 266 | .buf_prepare = gsc_m2m_buf_prepare, |
267 | .buf_queue = gsc_m2m_buf_queue, | 267 | .buf_queue = gsc_m2m_buf_queue, |
@@ -277,9 +277,10 @@ static int gsc_m2m_querycap(struct file *file, void *fh, | |||
277 | struct gsc_ctx *ctx = fh_to_ctx(fh); | 277 | struct gsc_ctx *ctx = fh_to_ctx(fh); |
278 | struct gsc_dev *gsc = ctx->gsc_dev; | 278 | struct gsc_dev *gsc = ctx->gsc_dev; |
279 | 279 | ||
280 | strlcpy(cap->driver, gsc->pdev->name, sizeof(cap->driver)); | 280 | strlcpy(cap->driver, GSC_MODULE_NAME, sizeof(cap->driver)); |
281 | strlcpy(cap->card, gsc->pdev->name, sizeof(cap->card)); | 281 | strlcpy(cap->card, GSC_MODULE_NAME " gscaler", sizeof(cap->card)); |
282 | strlcpy(cap->bus_info, "platform", sizeof(cap->bus_info)); | 282 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", |
283 | dev_name(&gsc->pdev->dev)); | ||
283 | cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE | | 284 | cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE | |
284 | V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; | 285 | V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; |
285 | 286 | ||
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index fdec499fbbda..964f4a681934 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c | |||
@@ -452,7 +452,7 @@ static void buffer_queue(struct vb2_buffer *vb) | |||
452 | spin_unlock_irqrestore(&fimc->slock, flags); | 452 | spin_unlock_irqrestore(&fimc->slock, flags); |
453 | } | 453 | } |
454 | 454 | ||
455 | static struct vb2_ops fimc_capture_qops = { | 455 | static const struct vb2_ops fimc_capture_qops = { |
456 | .queue_setup = queue_setup, | 456 | .queue_setup = queue_setup, |
457 | .buf_prepare = buffer_prepare, | 457 | .buf_prepare = buffer_prepare, |
458 | .buf_queue = buffer_queue, | 458 | .buf_queue = buffer_queue, |
@@ -1796,6 +1796,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, | |||
1796 | vid_cap->wb_fmt.code = fmt->mbus_code; | 1796 | vid_cap->wb_fmt.code = fmt->mbus_code; |
1797 | 1797 | ||
1798 | vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK; | 1798 | vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK; |
1799 | vfd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; | ||
1799 | ret = media_entity_pads_init(&vfd->entity, 1, &vid_cap->vd_pad); | 1800 | ret = media_entity_pads_init(&vfd->entity, 1, &vid_cap->vd_pad); |
1800 | if (ret) | 1801 | if (ret) |
1801 | goto err_free_ctx; | 1802 | goto err_free_ctx; |
diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c index 7521aa59b064..6bba4ca022be 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-i2c.c +++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.c | |||
@@ -55,26 +55,33 @@ static int fimc_is_i2c_probe(struct platform_device *pdev) | |||
55 | i2c_adap->algo = &fimc_is_i2c_algorithm; | 55 | i2c_adap->algo = &fimc_is_i2c_algorithm; |
56 | i2c_adap->class = I2C_CLASS_SPD; | 56 | i2c_adap->class = I2C_CLASS_SPD; |
57 | 57 | ||
58 | ret = i2c_add_adapter(i2c_adap); | ||
59 | if (ret < 0) { | ||
60 | dev_err(&pdev->dev, "failed to add I2C bus %s\n", | ||
61 | node->full_name); | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | platform_set_drvdata(pdev, isp_i2c); | 58 | platform_set_drvdata(pdev, isp_i2c); |
66 | |||
67 | pm_runtime_enable(&pdev->dev); | 59 | pm_runtime_enable(&pdev->dev); |
68 | pm_runtime_enable(&i2c_adap->dev); | ||
69 | 60 | ||
61 | ret = i2c_add_adapter(i2c_adap); | ||
62 | if (ret < 0) | ||
63 | goto err_pm_dis; | ||
64 | /* | ||
65 | * Client drivers of this adapter don't do any I2C transfers as that | ||
66 | * is handled by the ISP firmware. But we rely on the runtime PM | ||
67 | * state propagation from the clients up to the adapter driver so | ||
68 | * clear the ignore_children flags here. PM rutnime calls are not | ||
69 | * used in probe() handler of clients of this adapter so there is | ||
70 | * no issues with clearing the flag right after registering the I2C | ||
71 | * adapter. | ||
72 | */ | ||
73 | pm_suspend_ignore_children(&i2c_adap->dev, false); | ||
70 | return 0; | 74 | return 0; |
75 | |||
76 | err_pm_dis: | ||
77 | pm_runtime_disable(&pdev->dev); | ||
78 | return ret; | ||
71 | } | 79 | } |
72 | 80 | ||
73 | static int fimc_is_i2c_remove(struct platform_device *pdev) | 81 | static int fimc_is_i2c_remove(struct platform_device *pdev) |
74 | { | 82 | { |
75 | struct fimc_is_i2c *isp_i2c = platform_get_drvdata(pdev); | 83 | struct fimc_is_i2c *isp_i2c = platform_get_drvdata(pdev); |
76 | 84 | ||
77 | pm_runtime_disable(&isp_i2c->adapter.dev); | ||
78 | pm_runtime_disable(&pdev->dev); | 85 | pm_runtime_disable(&pdev->dev); |
79 | i2c_del_adapter(&isp_i2c->adapter); | 86 | i2c_del_adapter(&isp_i2c->adapter); |
80 | 87 | ||
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 32ca55f16677..518ad34f80d7 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c | |||
@@ -52,6 +52,9 @@ static char *fimc_is_clocks[ISS_CLKS_MAX] = { | |||
52 | [ISS_CLK_DRC] = "drc", | 52 | [ISS_CLK_DRC] = "drc", |
53 | [ISS_CLK_FD] = "fd", | 53 | [ISS_CLK_FD] = "fd", |
54 | [ISS_CLK_MCUISP] = "mcuisp", | 54 | [ISS_CLK_MCUISP] = "mcuisp", |
55 | [ISS_CLK_GICISP] = "gicisp", | ||
56 | [ISS_CLK_PWM_ISP] = "pwm_isp", | ||
57 | [ISS_CLK_MCUCTL_ISP] = "mcuctl_isp", | ||
55 | [ISS_CLK_UART] = "uart", | 58 | [ISS_CLK_UART] = "uart", |
56 | [ISS_CLK_ISP_DIV0] = "ispdiv0", | 59 | [ISS_CLK_ISP_DIV0] = "ispdiv0", |
57 | [ISS_CLK_ISP_DIV1] = "ispdiv1", | 60 | [ISS_CLK_ISP_DIV1] = "ispdiv1", |
@@ -165,6 +168,7 @@ static int fimc_is_parse_sensor_config(struct fimc_is *is, unsigned int index, | |||
165 | struct device_node *node) | 168 | struct device_node *node) |
166 | { | 169 | { |
167 | struct fimc_is_sensor *sensor = &is->sensor[index]; | 170 | struct fimc_is_sensor *sensor = &is->sensor[index]; |
171 | struct device_node *ep, *port; | ||
168 | u32 tmp = 0; | 172 | u32 tmp = 0; |
169 | int ret; | 173 | int ret; |
170 | 174 | ||
@@ -175,22 +179,25 @@ static int fimc_is_parse_sensor_config(struct fimc_is *is, unsigned int index, | |||
175 | return -EINVAL; | 179 | return -EINVAL; |
176 | } | 180 | } |
177 | 181 | ||
178 | node = of_graph_get_next_endpoint(node, NULL); | 182 | ep = of_graph_get_next_endpoint(node, NULL); |
179 | if (!node) | 183 | if (!ep) |
180 | return -ENXIO; | 184 | return -ENXIO; |
181 | 185 | ||
182 | node = of_graph_get_remote_port(node); | 186 | port = of_graph_get_remote_port(ep); |
183 | if (!node) | 187 | of_node_put(ep); |
188 | if (!port) | ||
184 | return -ENXIO; | 189 | return -ENXIO; |
185 | 190 | ||
186 | /* Use MIPI-CSIS channel id to determine the ISP I2C bus index. */ | 191 | /* Use MIPI-CSIS channel id to determine the ISP I2C bus index. */ |
187 | ret = of_property_read_u32(node, "reg", &tmp); | 192 | ret = of_property_read_u32(port, "reg", &tmp); |
188 | if (ret < 0) { | 193 | if (ret < 0) { |
189 | dev_err(&is->pdev->dev, "reg property not found at: %s\n", | 194 | dev_err(&is->pdev->dev, "reg property not found at: %s\n", |
190 | node->full_name); | 195 | port->full_name); |
196 | of_node_put(port); | ||
191 | return ret; | 197 | return ret; |
192 | } | 198 | } |
193 | 199 | ||
200 | of_node_put(port); | ||
194 | sensor->i2c_bus = tmp - FIMC_INPUT_MIPI_CSI2_0; | 201 | sensor->i2c_bus = tmp - FIMC_INPUT_MIPI_CSI2_0; |
195 | return 0; | 202 | return 0; |
196 | } | 203 | } |
@@ -845,13 +852,18 @@ static int fimc_is_probe(struct platform_device *pdev) | |||
845 | goto err_pm; | 852 | goto err_pm; |
846 | 853 | ||
847 | vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); | 854 | vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); |
855 | |||
856 | ret = of_platform_populate(dev->of_node, NULL, NULL, dev); | ||
857 | if (ret < 0) | ||
858 | goto err_pm; | ||
859 | |||
848 | /* | 860 | /* |
849 | * Register FIMC-IS V4L2 subdevs to this driver. The video nodes | 861 | * Register FIMC-IS V4L2 subdevs to this driver. The video nodes |
850 | * will be created within the subdev's registered() callback. | 862 | * will be created within the subdev's registered() callback. |
851 | */ | 863 | */ |
852 | ret = fimc_is_register_subdevs(is); | 864 | ret = fimc_is_register_subdevs(is); |
853 | if (ret < 0) | 865 | if (ret < 0) |
854 | goto err_pm; | 866 | goto err_of_dep; |
855 | 867 | ||
856 | ret = fimc_is_debugfs_create(is); | 868 | ret = fimc_is_debugfs_create(is); |
857 | if (ret < 0) | 869 | if (ret < 0) |
@@ -870,6 +882,8 @@ err_dfs: | |||
870 | fimc_is_debugfs_remove(is); | 882 | fimc_is_debugfs_remove(is); |
871 | err_sd: | 883 | err_sd: |
872 | fimc_is_unregister_subdevs(is); | 884 | fimc_is_unregister_subdevs(is); |
885 | err_of_dep: | ||
886 | of_platform_depopulate(dev); | ||
873 | err_pm: | 887 | err_pm: |
874 | if (!pm_runtime_enabled(dev)) | 888 | if (!pm_runtime_enabled(dev)) |
875 | fimc_is_runtime_suspend(dev); | 889 | fimc_is_runtime_suspend(dev); |
@@ -929,6 +943,7 @@ static int fimc_is_remove(struct platform_device *pdev) | |||
929 | if (!pm_runtime_status_suspended(dev)) | 943 | if (!pm_runtime_status_suspended(dev)) |
930 | fimc_is_runtime_suspend(dev); | 944 | fimc_is_runtime_suspend(dev); |
931 | free_irq(is->irq, is); | 945 | free_irq(is->irq, is); |
946 | of_platform_depopulate(dev); | ||
932 | fimc_is_unregister_subdevs(is); | 947 | fimc_is_unregister_subdevs(is); |
933 | vb2_dma_contig_clear_max_seg_size(dev); | 948 | vb2_dma_contig_clear_max_seg_size(dev); |
934 | fimc_is_put_clocks(is); | 949 | fimc_is_put_clocks(is); |
diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h index 3a82c6a214c7..ee05da034aa1 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.h +++ b/drivers/media/platform/exynos4-is/fimc-is.h | |||
@@ -77,6 +77,9 @@ enum { | |||
77 | ISS_CLK_DRC, | 77 | ISS_CLK_DRC, |
78 | ISS_CLK_FD, | 78 | ISS_CLK_FD, |
79 | ISS_CLK_MCUISP, | 79 | ISS_CLK_MCUISP, |
80 | ISS_CLK_GICISP, | ||
81 | ISS_CLK_PWM_ISP, | ||
82 | ISS_CLK_MCUCTL_ISP, | ||
80 | ISS_CLK_UART, | 83 | ISS_CLK_UART, |
81 | ISS_GATE_CLKS_MAX, | 84 | ISS_GATE_CLKS_MAX, |
82 | ISS_CLK_ISP_DIV0 = ISS_GATE_CLKS_MAX, | 85 | ISS_CLK_ISP_DIV0 = ISS_GATE_CLKS_MAX, |
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 293b807020c4..8efe9160ab34 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c | |||
@@ -705,6 +705,7 @@ int fimc_isp_subdev_create(struct fimc_isp *isp) | |||
705 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 705 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
706 | snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP"); | 706 | snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP"); |
707 | 707 | ||
708 | sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; | ||
708 | isp->subdev_pads[FIMC_ISP_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | 709 | isp->subdev_pads[FIMC_ISP_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; |
709 | isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_FIFO].flags = MEDIA_PAD_FL_SOURCE; | 710 | isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_FIFO].flags = MEDIA_PAD_FL_SOURCE; |
710 | isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_DMA].flags = MEDIA_PAD_FL_SOURCE; | 711 | isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_DMA].flags = MEDIA_PAD_FL_SOURCE; |
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index a0f149fb88e1..b91abf1c4d43 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c | |||
@@ -1432,6 +1432,7 @@ static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc) | |||
1432 | 1432 | ||
1433 | sd->ctrl_handler = handler; | 1433 | sd->ctrl_handler = handler; |
1434 | sd->internal_ops = &fimc_lite_subdev_internal_ops; | 1434 | sd->internal_ops = &fimc_lite_subdev_internal_ops; |
1435 | sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; | ||
1435 | sd->entity.ops = &fimc_lite_subdev_media_ops; | 1436 | sd->entity.ops = &fimc_lite_subdev_media_ops; |
1436 | sd->owner = THIS_MODULE; | 1437 | sd->owner = THIS_MODULE; |
1437 | v4l2_set_subdevdata(sd, fimc); | 1438 | v4l2_set_subdevdata(sd, fimc); |
@@ -1454,25 +1455,17 @@ static void fimc_lite_clk_put(struct fimc_lite *fimc) | |||
1454 | if (IS_ERR(fimc->clock)) | 1455 | if (IS_ERR(fimc->clock)) |
1455 | return; | 1456 | return; |
1456 | 1457 | ||
1457 | clk_unprepare(fimc->clock); | ||
1458 | clk_put(fimc->clock); | 1458 | clk_put(fimc->clock); |
1459 | fimc->clock = ERR_PTR(-EINVAL); | 1459 | fimc->clock = ERR_PTR(-EINVAL); |
1460 | } | 1460 | } |
1461 | 1461 | ||
1462 | static int fimc_lite_clk_get(struct fimc_lite *fimc) | 1462 | static int fimc_lite_clk_get(struct fimc_lite *fimc) |
1463 | { | 1463 | { |
1464 | int ret; | ||
1465 | |||
1466 | fimc->clock = clk_get(&fimc->pdev->dev, FLITE_CLK_NAME); | 1464 | fimc->clock = clk_get(&fimc->pdev->dev, FLITE_CLK_NAME); |
1467 | if (IS_ERR(fimc->clock)) | 1465 | if (IS_ERR(fimc->clock)) |
1468 | return PTR_ERR(fimc->clock); | 1466 | return PTR_ERR(fimc->clock); |
1469 | 1467 | ||
1470 | ret = clk_prepare(fimc->clock); | 1468 | return 0; |
1471 | if (ret < 0) { | ||
1472 | clk_put(fimc->clock); | ||
1473 | fimc->clock = ERR_PTR(-EINVAL); | ||
1474 | } | ||
1475 | return ret; | ||
1476 | } | 1469 | } |
1477 | 1470 | ||
1478 | static const struct of_device_id flite_of_match[]; | 1471 | static const struct of_device_id flite_of_match[]; |
@@ -1543,7 +1536,7 @@ static int fimc_lite_probe(struct platform_device *pdev) | |||
1543 | pm_runtime_enable(dev); | 1536 | pm_runtime_enable(dev); |
1544 | 1537 | ||
1545 | if (!pm_runtime_enabled(dev)) { | 1538 | if (!pm_runtime_enabled(dev)) { |
1546 | ret = clk_enable(fimc->clock); | 1539 | ret = clk_prepare_enable(fimc->clock); |
1547 | if (ret < 0) | 1540 | if (ret < 0) |
1548 | goto err_sd; | 1541 | goto err_sd; |
1549 | } | 1542 | } |
@@ -1568,7 +1561,7 @@ static int fimc_lite_runtime_resume(struct device *dev) | |||
1568 | { | 1561 | { |
1569 | struct fimc_lite *fimc = dev_get_drvdata(dev); | 1562 | struct fimc_lite *fimc = dev_get_drvdata(dev); |
1570 | 1563 | ||
1571 | clk_enable(fimc->clock); | 1564 | clk_prepare_enable(fimc->clock); |
1572 | return 0; | 1565 | return 0; |
1573 | } | 1566 | } |
1574 | 1567 | ||
@@ -1576,7 +1569,7 @@ static int fimc_lite_runtime_suspend(struct device *dev) | |||
1576 | { | 1569 | { |
1577 | struct fimc_lite *fimc = dev_get_drvdata(dev); | 1570 | struct fimc_lite *fimc = dev_get_drvdata(dev); |
1578 | 1571 | ||
1579 | clk_disable(fimc->clock); | 1572 | clk_disable_unprepare(fimc->clock); |
1580 | return 0; | 1573 | return 0; |
1581 | } | 1574 | } |
1582 | #endif | 1575 | #endif |
diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index b1309e114edb..6028e4fbaed3 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c | |||
@@ -219,7 +219,7 @@ static void fimc_buf_queue(struct vb2_buffer *vb) | |||
219 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); | 219 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); |
220 | } | 220 | } |
221 | 221 | ||
222 | static struct vb2_ops fimc_qops = { | 222 | static const struct vb2_ops fimc_qops = { |
223 | .queue_setup = fimc_queue_setup, | 223 | .queue_setup = fimc_queue_setup, |
224 | .buf_prepare = fimc_buf_prepare, | 224 | .buf_prepare = fimc_buf_prepare, |
225 | .buf_queue = fimc_buf_queue, | 225 | .buf_queue = fimc_buf_queue, |
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 891625e77ef5..1a1154a9dfa4 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c | |||
@@ -1190,6 +1190,10 @@ static int fimc_md_link_notify(struct media_link *link, unsigned int flags, | |||
1190 | return ret ? -EPIPE : 0; | 1190 | return ret ? -EPIPE : 0; |
1191 | } | 1191 | } |
1192 | 1192 | ||
1193 | static const struct media_device_ops fimc_md_ops = { | ||
1194 | .link_notify = fimc_md_link_notify, | ||
1195 | }; | ||
1196 | |||
1193 | static ssize_t fimc_md_sysfs_show(struct device *dev, | 1197 | static ssize_t fimc_md_sysfs_show(struct device *dev, |
1194 | struct device_attribute *attr, char *buf) | 1198 | struct device_attribute *attr, char *buf) |
1195 | { | 1199 | { |
@@ -1416,7 +1420,7 @@ static int fimc_md_probe(struct platform_device *pdev) | |||
1416 | 1420 | ||
1417 | strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC", | 1421 | strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC", |
1418 | sizeof(fmd->media_dev.model)); | 1422 | sizeof(fmd->media_dev.model)); |
1419 | fmd->media_dev.link_notify = fimc_md_link_notify; | 1423 | fmd->media_dev.ops = &fimc_md_ops; |
1420 | fmd->media_dev.dev = dev; | 1424 | fmd->media_dev.dev = dev; |
1421 | 1425 | ||
1422 | v4l2_dev = &fmd->v4l2_dev; | 1426 | v4l2_dev = &fmd->v4l2_dev; |
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 86e681daa89d..befd9fc0adc4 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c | |||
@@ -853,6 +853,7 @@ static int s5pcsis_probe(struct platform_device *pdev) | |||
853 | state->format.width = S5PCSIS_DEF_PIX_WIDTH; | 853 | state->format.width = S5PCSIS_DEF_PIX_WIDTH; |
854 | state->format.height = S5PCSIS_DEF_PIX_HEIGHT; | 854 | state->format.height = S5PCSIS_DEF_PIX_HEIGHT; |
855 | 855 | ||
856 | state->sd.entity.function = MEDIA_ENT_F_IO_V4L; | ||
856 | state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | 857 | state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; |
857 | state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; | 858 | state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; |
858 | ret = media_entity_pads_init(&state->sd.entity, | 859 | ret = media_entity_pads_init(&state->sd.entity, |
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 0fcb5c78031d..bedc7cc4c7d6 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c | |||
@@ -852,7 +852,7 @@ static void deinterlace_buf_queue(struct vb2_buffer *vb) | |||
852 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); | 852 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); |
853 | } | 853 | } |
854 | 854 | ||
855 | static struct vb2_ops deinterlace_qops = { | 855 | static const struct vb2_ops deinterlace_qops = { |
856 | .queue_setup = deinterlace_queue_setup, | 856 | .queue_setup = deinterlace_queue_setup, |
857 | .buf_prepare = deinterlace_buf_prepare, | 857 | .buf_prepare = deinterlace_buf_prepare, |
858 | .buf_queue = deinterlace_buf_queue, | 858 | .buf_queue = deinterlace_buf_queue, |
@@ -1016,7 +1016,7 @@ static int deinterlace_probe(struct platform_device *pdev) | |||
1016 | return -ENODEV; | 1016 | return -ENODEV; |
1017 | 1017 | ||
1018 | if (!dma_has_cap(DMA_INTERLEAVE, pcdev->dma_chan->device->cap_mask)) { | 1018 | if (!dma_has_cap(DMA_INTERLEAVE, pcdev->dma_chan->device->cap_mask)) { |
1019 | v4l2_err(&pcdev->v4l2_dev, "DMA does not support INTERLEAVE\n"); | 1019 | dev_err(&pdev->dev, "DMA does not support INTERLEAVE\n"); |
1020 | goto rel_dma; | 1020 | goto rel_dma; |
1021 | } | 1021 | } |
1022 | 1022 | ||
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 3a8e6958adae..c8eaa41c00e6 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | |||
@@ -239,7 +239,7 @@ struct mtk_vcodec_ctx { | |||
239 | enum mtk_encode_param param_change; | 239 | enum mtk_encode_param param_change; |
240 | struct mtk_enc_params enc_params; | 240 | struct mtk_enc_params enc_params; |
241 | 241 | ||
242 | struct venc_common_if *enc_if; | 242 | const struct venc_common_if *enc_if; |
243 | unsigned long drv_handle; | 243 | unsigned long drv_handle; |
244 | 244 | ||
245 | int int_cond; | 245 | int int_cond; |
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index 2c5719ac23b2..1b1a28abbf1f 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c | |||
@@ -243,6 +243,8 @@ static int vidioc_venc_s_parm(struct file *file, void *priv, | |||
243 | a->parm.output.timeperframe.numerator; | 243 | a->parm.output.timeperframe.numerator; |
244 | ctx->param_change |= MTK_ENCODE_PARAM_FRAMERATE; | 244 | ctx->param_change |= MTK_ENCODE_PARAM_FRAMERATE; |
245 | 245 | ||
246 | a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; | ||
247 | |||
246 | return 0; | 248 | return 0; |
247 | } | 249 | } |
248 | 250 | ||
@@ -254,6 +256,7 @@ static int vidioc_venc_g_parm(struct file *file, void *priv, | |||
254 | if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | 256 | if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) |
255 | return -EINVAL; | 257 | return -EINVAL; |
256 | 258 | ||
259 | a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; | ||
257 | a->parm.output.timeperframe.denominator = | 260 | a->parm.output.timeperframe.denominator = |
258 | ctx->enc_params.framerate_num; | 261 | ctx->enc_params.framerate_num; |
259 | a->parm.output.timeperframe.numerator = | 262 | a->parm.output.timeperframe.numerator = |
@@ -621,6 +624,69 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, | |||
621 | return vidioc_try_fmt(f, fmt); | 624 | return vidioc_try_fmt(f, fmt); |
622 | } | 625 | } |
623 | 626 | ||
627 | static int vidioc_venc_g_selection(struct file *file, void *priv, | ||
628 | struct v4l2_selection *s) | ||
629 | { | ||
630 | struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); | ||
631 | struct mtk_q_data *q_data; | ||
632 | |||
633 | if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
634 | return -EINVAL; | ||
635 | |||
636 | q_data = mtk_venc_get_q_data(ctx, s->type); | ||
637 | if (!q_data) | ||
638 | return -EINVAL; | ||
639 | |||
640 | switch (s->target) { | ||
641 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
642 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
643 | s->r.top = 0; | ||
644 | s->r.left = 0; | ||
645 | s->r.width = q_data->coded_width; | ||
646 | s->r.height = q_data->coded_height; | ||
647 | break; | ||
648 | case V4L2_SEL_TGT_CROP: | ||
649 | s->r.top = 0; | ||
650 | s->r.left = 0; | ||
651 | s->r.width = q_data->visible_width; | ||
652 | s->r.height = q_data->visible_height; | ||
653 | break; | ||
654 | default: | ||
655 | return -EINVAL; | ||
656 | } | ||
657 | |||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | static int vidioc_venc_s_selection(struct file *file, void *priv, | ||
662 | struct v4l2_selection *s) | ||
663 | { | ||
664 | struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); | ||
665 | struct mtk_q_data *q_data; | ||
666 | |||
667 | if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
668 | return -EINVAL; | ||
669 | |||
670 | q_data = mtk_venc_get_q_data(ctx, s->type); | ||
671 | if (!q_data) | ||
672 | return -EINVAL; | ||
673 | |||
674 | switch (s->target) { | ||
675 | case V4L2_SEL_TGT_CROP: | ||
676 | /* Only support crop from (0,0) */ | ||
677 | s->r.top = 0; | ||
678 | s->r.left = 0; | ||
679 | s->r.width = min(s->r.width, q_data->coded_width); | ||
680 | s->r.height = min(s->r.height, q_data->coded_height); | ||
681 | q_data->visible_width = s->r.width; | ||
682 | q_data->visible_height = s->r.height; | ||
683 | break; | ||
684 | default: | ||
685 | return -EINVAL; | ||
686 | } | ||
687 | return 0; | ||
688 | } | ||
689 | |||
624 | static int vidioc_venc_qbuf(struct file *file, void *priv, | 690 | static int vidioc_venc_qbuf(struct file *file, void *priv, |
625 | struct v4l2_buffer *buf) | 691 | struct v4l2_buffer *buf) |
626 | { | 692 | { |
@@ -679,6 +745,9 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = { | |||
679 | 745 | ||
680 | .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, | 746 | .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, |
681 | .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, | 747 | .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, |
748 | |||
749 | .vidioc_g_selection = vidioc_venc_g_selection, | ||
750 | .vidioc_s_selection = vidioc_venc_s_selection, | ||
682 | }; | 751 | }; |
683 | 752 | ||
684 | static int vb2ops_venc_queue_setup(struct vb2_queue *vq, | 753 | static int vb2ops_venc_queue_setup(struct vb2_queue *vq, |
@@ -854,7 +923,7 @@ static void vb2ops_venc_stop_streaming(struct vb2_queue *q) | |||
854 | ctx->state = MTK_STATE_FREE; | 923 | ctx->state = MTK_STATE_FREE; |
855 | } | 924 | } |
856 | 925 | ||
857 | static struct vb2_ops mtk_venc_vb2_ops = { | 926 | static const struct vb2_ops mtk_venc_vb2_ops = { |
858 | .queue_setup = vb2ops_venc_queue_setup, | 927 | .queue_setup = vb2ops_venc_queue_setup, |
859 | .buf_prepare = vb2ops_venc_buf_prepare, | 928 | .buf_prepare = vb2ops_venc_buf_prepare, |
860 | .buf_queue = vb2ops_venc_buf_queue, | 929 | .buf_queue = vb2ops_venc_buf_queue, |
diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c index 63d4be4ff327..b76c80bdf30b 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c | |||
@@ -664,16 +664,16 @@ static int h264_enc_deinit(unsigned long handle) | |||
664 | return ret; | 664 | return ret; |
665 | } | 665 | } |
666 | 666 | ||
667 | static struct venc_common_if venc_h264_if = { | 667 | static const struct venc_common_if venc_h264_if = { |
668 | h264_enc_init, | 668 | h264_enc_init, |
669 | h264_enc_encode, | 669 | h264_enc_encode, |
670 | h264_enc_set_param, | 670 | h264_enc_set_param, |
671 | h264_enc_deinit, | 671 | h264_enc_deinit, |
672 | }; | 672 | }; |
673 | 673 | ||
674 | struct venc_common_if *get_h264_enc_comm_if(void); | 674 | const struct venc_common_if *get_h264_enc_comm_if(void); |
675 | 675 | ||
676 | struct venc_common_if *get_h264_enc_comm_if(void) | 676 | const struct venc_common_if *get_h264_enc_comm_if(void) |
677 | { | 677 | { |
678 | return &venc_h264_if; | 678 | return &venc_h264_if; |
679 | } | 679 | } |
diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c index 6d9758479f9a..544f57186243 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c | |||
@@ -469,16 +469,16 @@ static int vp8_enc_deinit(unsigned long handle) | |||
469 | return ret; | 469 | return ret; |
470 | } | 470 | } |
471 | 471 | ||
472 | static struct venc_common_if venc_vp8_if = { | 472 | static const struct venc_common_if venc_vp8_if = { |
473 | vp8_enc_init, | 473 | vp8_enc_init, |
474 | vp8_enc_encode, | 474 | vp8_enc_encode, |
475 | vp8_enc_set_param, | 475 | vp8_enc_set_param, |
476 | vp8_enc_deinit, | 476 | vp8_enc_deinit, |
477 | }; | 477 | }; |
478 | 478 | ||
479 | struct venc_common_if *get_vp8_enc_comm_if(void); | 479 | const struct venc_common_if *get_vp8_enc_comm_if(void); |
480 | 480 | ||
481 | struct venc_common_if *get_vp8_enc_comm_if(void) | 481 | const struct venc_common_if *get_vp8_enc_comm_if(void) |
482 | { | 482 | { |
483 | return &venc_vp8_if; | 483 | return &venc_vp8_if; |
484 | } | 484 | } |
diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.c b/drivers/media/platform/mtk-vcodec/venc_drv_if.c index c4c83e7189c3..d02d5f1df279 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.c | |||
@@ -26,8 +26,8 @@ | |||
26 | #include "mtk_vcodec_enc_pm.h" | 26 | #include "mtk_vcodec_enc_pm.h" |
27 | #include "mtk_vpu.h" | 27 | #include "mtk_vpu.h" |
28 | 28 | ||
29 | struct venc_common_if *get_h264_enc_comm_if(void); | 29 | const struct venc_common_if *get_h264_enc_comm_if(void); |
30 | struct venc_common_if *get_vp8_enc_comm_if(void); | 30 | const struct venc_common_if *get_vp8_enc_comm_if(void); |
31 | 31 | ||
32 | int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) | 32 | int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) |
33 | { | 33 | { |
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index c639406fe72e..e68d271b10af 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c | |||
@@ -743,7 +743,7 @@ static void emmaprp_buf_queue(struct vb2_buffer *vb) | |||
743 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); | 743 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); |
744 | } | 744 | } |
745 | 745 | ||
746 | static struct vb2_ops emmaprp_qops = { | 746 | static const struct vb2_ops emmaprp_qops = { |
747 | .queue_setup = emmaprp_queue_setup, | 747 | .queue_setup = emmaprp_queue_setup, |
748 | .buf_prepare = emmaprp_buf_prepare, | 748 | .buf_prepare = emmaprp_buf_prepare, |
749 | .buf_queue = emmaprp_buf_queue, | 749 | .buf_queue = emmaprp_buf_queue, |
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 6b01e126fe73..e668dde6d857 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c | |||
@@ -1247,36 +1247,33 @@ static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, | |||
1247 | return 0; | 1247 | return 0; |
1248 | } | 1248 | } |
1249 | 1249 | ||
1250 | static int vidioc_cropcap(struct file *file, void *fh, | 1250 | static int vidioc_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) |
1251 | struct v4l2_cropcap *cropcap) | ||
1252 | { | 1251 | { |
1253 | struct omap_vout_device *vout = fh; | 1252 | struct omap_vout_device *vout = fh; |
1254 | struct v4l2_pix_format *pix = &vout->pix; | 1253 | struct v4l2_pix_format *pix = &vout->pix; |
1255 | 1254 | ||
1256 | if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | 1255 | if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) |
1257 | return -EINVAL; | 1256 | return -EINVAL; |
1258 | 1257 | ||
1259 | /* Width and height are always even */ | 1258 | switch (sel->target) { |
1260 | cropcap->bounds.width = pix->width & ~1; | 1259 | case V4L2_SEL_TGT_CROP: |
1261 | cropcap->bounds.height = pix->height & ~1; | 1260 | sel->r = vout->crop; |
1262 | 1261 | break; | |
1263 | omap_vout_default_crop(&vout->pix, &vout->fbuf, &cropcap->defrect); | 1262 | case V4L2_SEL_TGT_CROP_DEFAULT: |
1264 | cropcap->pixelaspect.numerator = 1; | 1263 | omap_vout_default_crop(&vout->pix, &vout->fbuf, &sel->r); |
1265 | cropcap->pixelaspect.denominator = 1; | 1264 | break; |
1266 | return 0; | 1265 | case V4L2_SEL_TGT_CROP_BOUNDS: |
1267 | } | 1266 | /* Width and height are always even */ |
1268 | 1267 | sel->r.width = pix->width & ~1; | |
1269 | static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) | 1268 | sel->r.height = pix->height & ~1; |
1270 | { | 1269 | break; |
1271 | struct omap_vout_device *vout = fh; | 1270 | default: |
1272 | |||
1273 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
1274 | return -EINVAL; | 1271 | return -EINVAL; |
1275 | crop->c = vout->crop; | 1272 | } |
1276 | return 0; | 1273 | return 0; |
1277 | } | 1274 | } |
1278 | 1275 | ||
1279 | static int vidioc_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) | 1276 | static int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection *sel) |
1280 | { | 1277 | { |
1281 | int ret = -EINVAL; | 1278 | int ret = -EINVAL; |
1282 | struct omap_vout_device *vout = fh; | 1279 | struct omap_vout_device *vout = fh; |
@@ -1285,6 +1282,12 @@ static int vidioc_s_crop(struct file *file, void *fh, const struct v4l2_crop *cr | |||
1285 | struct omap_video_timings *timing; | 1282 | struct omap_video_timings *timing; |
1286 | struct omap_dss_device *dssdev; | 1283 | struct omap_dss_device *dssdev; |
1287 | 1284 | ||
1285 | if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
1286 | return -EINVAL; | ||
1287 | |||
1288 | if (sel->target != V4L2_SEL_TGT_CROP) | ||
1289 | return -EINVAL; | ||
1290 | |||
1288 | if (vout->streaming) | 1291 | if (vout->streaming) |
1289 | return -EBUSY; | 1292 | return -EBUSY; |
1290 | 1293 | ||
@@ -1309,9 +1312,8 @@ static int vidioc_s_crop(struct file *file, void *fh, const struct v4l2_crop *cr | |||
1309 | vout->fbuf.fmt.width = timing->x_res; | 1312 | vout->fbuf.fmt.width = timing->x_res; |
1310 | } | 1313 | } |
1311 | 1314 | ||
1312 | if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | 1315 | ret = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win, |
1313 | ret = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win, | 1316 | &vout->fbuf, &sel->r); |
1314 | &vout->fbuf, &crop->c); | ||
1315 | 1317 | ||
1316 | s_crop_err: | 1318 | s_crop_err: |
1317 | mutex_unlock(&vout->lock); | 1319 | mutex_unlock(&vout->lock); |
@@ -1780,9 +1782,8 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = { | |||
1780 | .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_overlay, | 1782 | .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_overlay, |
1781 | .vidioc_s_fmt_vid_out_overlay = vidioc_s_fmt_vid_overlay, | 1783 | .vidioc_s_fmt_vid_out_overlay = vidioc_s_fmt_vid_overlay, |
1782 | .vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_overlay, | 1784 | .vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_overlay, |
1783 | .vidioc_cropcap = vidioc_cropcap, | 1785 | .vidioc_g_selection = vidioc_g_selection, |
1784 | .vidioc_g_crop = vidioc_g_crop, | 1786 | .vidioc_s_selection = vidioc_s_selection, |
1785 | .vidioc_s_crop = vidioc_s_crop, | ||
1786 | .vidioc_reqbufs = vidioc_reqbufs, | 1787 | .vidioc_reqbufs = vidioc_reqbufs, |
1787 | .vidioc_querybuf = vidioc_querybuf, | 1788 | .vidioc_querybuf = vidioc_querybuf, |
1788 | .vidioc_qbuf = vidioc_qbuf, | 1789 | .vidioc_qbuf = vidioc_qbuf, |
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 5d54e2c6c16b..0321d84addc7 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c | |||
@@ -657,6 +657,10 @@ static irqreturn_t isp_isr(int irq, void *_isp) | |||
657 | return IRQ_HANDLED; | 657 | return IRQ_HANDLED; |
658 | } | 658 | } |
659 | 659 | ||
660 | static const struct media_device_ops isp_media_ops = { | ||
661 | .link_notify = v4l2_pipeline_link_notify, | ||
662 | }; | ||
663 | |||
660 | /* ----------------------------------------------------------------------------- | 664 | /* ----------------------------------------------------------------------------- |
661 | * Pipeline stream management | 665 | * Pipeline stream management |
662 | */ | 666 | */ |
@@ -1680,7 +1684,7 @@ static int isp_register_entities(struct isp_device *isp) | |||
1680 | strlcpy(isp->media_dev.model, "TI OMAP3 ISP", | 1684 | strlcpy(isp->media_dev.model, "TI OMAP3 ISP", |
1681 | sizeof(isp->media_dev.model)); | 1685 | sizeof(isp->media_dev.model)); |
1682 | isp->media_dev.hw_revision = isp->revision; | 1686 | isp->media_dev.hw_revision = isp->revision; |
1683 | isp->media_dev.link_notify = v4l2_pipeline_link_notify; | 1687 | isp->media_dev.ops = &isp_media_ops; |
1684 | media_device_init(&isp->media_dev); | 1688 | media_device_init(&isp->media_dev); |
1685 | 1689 | ||
1686 | isp->v4l2_dev.mdev = &isp->media_dev; | 1690 | isp->v4l2_dev.mdev = &isp->media_dev; |
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 7d9f35976d18..7354469670b7 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c | |||
@@ -772,40 +772,45 @@ isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format) | |||
772 | } | 772 | } |
773 | 773 | ||
774 | static int | 774 | static int |
775 | isp_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) | 775 | isp_video_get_selection(struct file *file, void *fh, struct v4l2_selection *sel) |
776 | { | ||
777 | struct isp_video *video = video_drvdata(file); | ||
778 | struct v4l2_subdev *subdev; | ||
779 | int ret; | ||
780 | |||
781 | subdev = isp_video_remote_subdev(video, NULL); | ||
782 | if (subdev == NULL) | ||
783 | return -EINVAL; | ||
784 | |||
785 | mutex_lock(&video->mutex); | ||
786 | ret = v4l2_subdev_call(subdev, video, cropcap, cropcap); | ||
787 | mutex_unlock(&video->mutex); | ||
788 | |||
789 | return ret == -ENOIOCTLCMD ? -ENOTTY : ret; | ||
790 | } | ||
791 | |||
792 | static int | ||
793 | isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop) | ||
794 | { | 776 | { |
795 | struct isp_video *video = video_drvdata(file); | 777 | struct isp_video *video = video_drvdata(file); |
796 | struct v4l2_subdev_format format; | 778 | struct v4l2_subdev_format format; |
797 | struct v4l2_subdev *subdev; | 779 | struct v4l2_subdev *subdev; |
780 | struct v4l2_subdev_selection sdsel = { | ||
781 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
782 | .target = sel->target, | ||
783 | }; | ||
798 | u32 pad; | 784 | u32 pad; |
799 | int ret; | 785 | int ret; |
800 | 786 | ||
787 | switch (sel->target) { | ||
788 | case V4L2_SEL_TGT_CROP: | ||
789 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
790 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
791 | if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
792 | return -EINVAL; | ||
793 | break; | ||
794 | case V4L2_SEL_TGT_COMPOSE: | ||
795 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
796 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: | ||
797 | if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
798 | return -EINVAL; | ||
799 | break; | ||
800 | default: | ||
801 | return -EINVAL; | ||
802 | } | ||
801 | subdev = isp_video_remote_subdev(video, &pad); | 803 | subdev = isp_video_remote_subdev(video, &pad); |
802 | if (subdev == NULL) | 804 | if (subdev == NULL) |
803 | return -EINVAL; | 805 | return -EINVAL; |
804 | 806 | ||
805 | /* Try the get crop operation first and fallback to get format if not | 807 | /* Try the get selection operation first and fallback to get format if not |
806 | * implemented. | 808 | * implemented. |
807 | */ | 809 | */ |
808 | ret = v4l2_subdev_call(subdev, video, g_crop, crop); | 810 | sdsel.pad = pad; |
811 | ret = v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel); | ||
812 | if (!ret) | ||
813 | sel->r = sdsel.r; | ||
809 | if (ret != -ENOIOCTLCMD) | 814 | if (ret != -ENOIOCTLCMD) |
810 | return ret; | 815 | return ret; |
811 | 816 | ||
@@ -815,28 +820,50 @@ isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop) | |||
815 | if (ret < 0) | 820 | if (ret < 0) |
816 | return ret == -ENOIOCTLCMD ? -ENOTTY : ret; | 821 | return ret == -ENOIOCTLCMD ? -ENOTTY : ret; |
817 | 822 | ||
818 | crop->c.left = 0; | 823 | sel->r.left = 0; |
819 | crop->c.top = 0; | 824 | sel->r.top = 0; |
820 | crop->c.width = format.format.width; | 825 | sel->r.width = format.format.width; |
821 | crop->c.height = format.format.height; | 826 | sel->r.height = format.format.height; |
822 | 827 | ||
823 | return 0; | 828 | return 0; |
824 | } | 829 | } |
825 | 830 | ||
826 | static int | 831 | static int |
827 | isp_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop) | 832 | isp_video_set_selection(struct file *file, void *fh, struct v4l2_selection *sel) |
828 | { | 833 | { |
829 | struct isp_video *video = video_drvdata(file); | 834 | struct isp_video *video = video_drvdata(file); |
830 | struct v4l2_subdev *subdev; | 835 | struct v4l2_subdev *subdev; |
836 | struct v4l2_subdev_selection sdsel = { | ||
837 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
838 | .target = sel->target, | ||
839 | .flags = sel->flags, | ||
840 | .r = sel->r, | ||
841 | }; | ||
842 | u32 pad; | ||
831 | int ret; | 843 | int ret; |
832 | 844 | ||
833 | subdev = isp_video_remote_subdev(video, NULL); | 845 | switch (sel->target) { |
846 | case V4L2_SEL_TGT_CROP: | ||
847 | if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
848 | return -EINVAL; | ||
849 | break; | ||
850 | case V4L2_SEL_TGT_COMPOSE: | ||
851 | if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
852 | return -EINVAL; | ||
853 | break; | ||
854 | default: | ||
855 | return -EINVAL; | ||
856 | } | ||
857 | subdev = isp_video_remote_subdev(video, &pad); | ||
834 | if (subdev == NULL) | 858 | if (subdev == NULL) |
835 | return -EINVAL; | 859 | return -EINVAL; |
836 | 860 | ||
861 | sdsel.pad = pad; | ||
837 | mutex_lock(&video->mutex); | 862 | mutex_lock(&video->mutex); |
838 | ret = v4l2_subdev_call(subdev, video, s_crop, crop); | 863 | ret = v4l2_subdev_call(subdev, pad, set_selection, NULL, &sdsel); |
839 | mutex_unlock(&video->mutex); | 864 | mutex_unlock(&video->mutex); |
865 | if (!ret) | ||
866 | sel->r = sdsel.r; | ||
840 | 867 | ||
841 | return ret == -ENOIOCTLCMD ? -ENOTTY : ret; | 868 | return ret == -ENOIOCTLCMD ? -ENOTTY : ret; |
842 | } | 869 | } |
@@ -1252,9 +1279,8 @@ static const struct v4l2_ioctl_ops isp_video_ioctl_ops = { | |||
1252 | .vidioc_g_fmt_vid_out = isp_video_get_format, | 1279 | .vidioc_g_fmt_vid_out = isp_video_get_format, |
1253 | .vidioc_s_fmt_vid_out = isp_video_set_format, | 1280 | .vidioc_s_fmt_vid_out = isp_video_set_format, |
1254 | .vidioc_try_fmt_vid_out = isp_video_try_format, | 1281 | .vidioc_try_fmt_vid_out = isp_video_try_format, |
1255 | .vidioc_cropcap = isp_video_cropcap, | 1282 | .vidioc_g_selection = isp_video_get_selection, |
1256 | .vidioc_g_crop = isp_video_get_crop, | 1283 | .vidioc_s_selection = isp_video_set_selection, |
1257 | .vidioc_s_crop = isp_video_set_crop, | ||
1258 | .vidioc_g_parm = isp_video_get_param, | 1284 | .vidioc_g_parm = isp_video_get_param, |
1259 | .vidioc_s_parm = isp_video_set_param, | 1285 | .vidioc_s_parm = isp_video_set_param, |
1260 | .vidioc_reqbufs = isp_video_reqbufs, | 1286 | .vidioc_reqbufs = isp_video_reqbufs, |
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/pxa_camera.c index 2aaf4a8f71a0..c12209c701d3 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2006, Sascha Hauer, Pengutronix | 4 | * Copyright (C) 2006, Sascha Hauer, Pengutronix |
5 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> | 5 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> |
6 | * Copyright (C) 2016, Robert Jarzmik <robert.jarzmik@free.fr> | ||
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -14,6 +15,7 @@ | |||
14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
15 | #include <linux/io.h> | 16 | #include <linux/io.h> |
16 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/device.h> | ||
17 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
18 | #include <linux/err.h> | 20 | #include <linux/err.h> |
19 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
@@ -22,8 +24,8 @@ | |||
22 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
23 | #include <linux/mm.h> | 25 | #include <linux/mm.h> |
24 | #include <linux/moduleparam.h> | 26 | #include <linux/moduleparam.h> |
27 | #include <linux/of.h> | ||
25 | #include <linux/time.h> | 28 | #include <linux/time.h> |
26 | #include <linux/device.h> | ||
27 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
28 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
29 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
@@ -32,13 +34,15 @@ | |||
32 | #include <linux/dma-mapping.h> | 34 | #include <linux/dma-mapping.h> |
33 | #include <linux/dma/pxa-dma.h> | 35 | #include <linux/dma/pxa-dma.h> |
34 | 36 | ||
37 | #include <media/v4l2-async.h> | ||
38 | #include <media/v4l2-clk.h> | ||
35 | #include <media/v4l2-common.h> | 39 | #include <media/v4l2-common.h> |
36 | #include <media/v4l2-dev.h> | 40 | #include <media/v4l2-device.h> |
37 | #include <media/videobuf-dma-sg.h> | 41 | #include <media/v4l2-ioctl.h> |
38 | #include <media/soc_camera.h> | ||
39 | #include <media/drv-intf/soc_mediabus.h> | ||
40 | #include <media/v4l2-of.h> | 42 | #include <media/v4l2-of.h> |
41 | 43 | ||
44 | #include <media/videobuf2-dma-sg.h> | ||
45 | |||
42 | #include <linux/videodev2.h> | 46 | #include <linux/videodev2.h> |
43 | 47 | ||
44 | #include <linux/platform_data/media/camera-pxa.h> | 48 | #include <linux/platform_data/media/camera-pxa.h> |
@@ -46,6 +50,9 @@ | |||
46 | #define PXA_CAM_VERSION "0.0.6" | 50 | #define PXA_CAM_VERSION "0.0.6" |
47 | #define PXA_CAM_DRV_NAME "pxa27x-camera" | 51 | #define PXA_CAM_DRV_NAME "pxa27x-camera" |
48 | 52 | ||
53 | #define DEFAULT_WIDTH 640 | ||
54 | #define DEFAULT_HEIGHT 480 | ||
55 | |||
49 | /* Camera Interface */ | 56 | /* Camera Interface */ |
50 | #define CICR0 0x0000 | 57 | #define CICR0 0x0000 |
51 | #define CICR1 0x0004 | 58 | #define CICR1 0x0004 |
@@ -168,6 +175,462 @@ | |||
168 | CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \ | 175 | CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \ |
169 | CICR0_EOFM | CICR0_FOM) | 176 | CICR0_EOFM | CICR0_FOM) |
170 | 177 | ||
178 | #define sensor_call(cam, o, f, args...) \ | ||
179 | v4l2_subdev_call(cam->sensor, o, f, ##args) | ||
180 | |||
181 | /* | ||
182 | * Format handling | ||
183 | */ | ||
184 | |||
185 | /** | ||
186 | * enum pxa_mbus_packing - data packing types on the media-bus | ||
187 | * @PXA_MBUS_PACKING_NONE: no packing, bit-for-bit transfer to RAM, one | ||
188 | * sample represents one pixel | ||
189 | * @PXA_MBUS_PACKING_2X8_PADHI: 16 bits transferred in 2 8-bit samples, in the | ||
190 | * possibly incomplete byte high bits are padding | ||
191 | * @PXA_MBUS_PACKING_EXTEND16: sample width (e.g., 10 bits) has to be extended | ||
192 | * to 16 bits | ||
193 | */ | ||
194 | enum pxa_mbus_packing { | ||
195 | PXA_MBUS_PACKING_NONE, | ||
196 | PXA_MBUS_PACKING_2X8_PADHI, | ||
197 | PXA_MBUS_PACKING_EXTEND16, | ||
198 | }; | ||
199 | |||
200 | /** | ||
201 | * enum pxa_mbus_order - sample order on the media bus | ||
202 | * @PXA_MBUS_ORDER_LE: least significant sample first | ||
203 | * @PXA_MBUS_ORDER_BE: most significant sample first | ||
204 | */ | ||
205 | enum pxa_mbus_order { | ||
206 | PXA_MBUS_ORDER_LE, | ||
207 | PXA_MBUS_ORDER_BE, | ||
208 | }; | ||
209 | |||
210 | /** | ||
211 | * enum pxa_mbus_layout - planes layout in memory | ||
212 | * @PXA_MBUS_LAYOUT_PACKED: color components packed | ||
213 | * @PXA_MBUS_LAYOUT_PLANAR_2Y_U_V: YUV components stored in 3 planes (4:2:2) | ||
214 | * @PXA_MBUS_LAYOUT_PLANAR_2Y_C: YUV components stored in a luma and a | ||
215 | * chroma plane (C plane is half the size | ||
216 | * of Y plane) | ||
217 | * @PXA_MBUS_LAYOUT_PLANAR_Y_C: YUV components stored in a luma and a | ||
218 | * chroma plane (C plane is the same size | ||
219 | * as Y plane) | ||
220 | */ | ||
221 | enum pxa_mbus_layout { | ||
222 | PXA_MBUS_LAYOUT_PACKED = 0, | ||
223 | PXA_MBUS_LAYOUT_PLANAR_2Y_U_V, | ||
224 | PXA_MBUS_LAYOUT_PLANAR_2Y_C, | ||
225 | PXA_MBUS_LAYOUT_PLANAR_Y_C, | ||
226 | }; | ||
227 | |||
228 | /** | ||
229 | * struct pxa_mbus_pixelfmt - Data format on the media bus | ||
230 | * @name: Name of the format | ||
231 | * @fourcc: Fourcc code, that will be obtained if the data is | ||
232 | * stored in memory in the following way: | ||
233 | * @packing: Type of sample-packing, that has to be used | ||
234 | * @order: Sample order when storing in memory | ||
235 | * @bits_per_sample: How many bits the bridge has to sample | ||
236 | */ | ||
237 | struct pxa_mbus_pixelfmt { | ||
238 | const char *name; | ||
239 | u32 fourcc; | ||
240 | enum pxa_mbus_packing packing; | ||
241 | enum pxa_mbus_order order; | ||
242 | enum pxa_mbus_layout layout; | ||
243 | u8 bits_per_sample; | ||
244 | }; | ||
245 | |||
246 | /** | ||
247 | * struct pxa_mbus_lookup - Lookup FOURCC IDs by mediabus codes for pass-through | ||
248 | * @code: mediabus pixel-code | ||
249 | * @fmt: pixel format description | ||
250 | */ | ||
251 | struct pxa_mbus_lookup { | ||
252 | u32 code; | ||
253 | struct pxa_mbus_pixelfmt fmt; | ||
254 | }; | ||
255 | |||
256 | static const struct pxa_mbus_lookup mbus_fmt[] = { | ||
257 | { | ||
258 | .code = MEDIA_BUS_FMT_YUYV8_2X8, | ||
259 | .fmt = { | ||
260 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
261 | .name = "YUYV", | ||
262 | .bits_per_sample = 8, | ||
263 | .packing = PXA_MBUS_PACKING_2X8_PADHI, | ||
264 | .order = PXA_MBUS_ORDER_LE, | ||
265 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
266 | }, | ||
267 | }, { | ||
268 | .code = MEDIA_BUS_FMT_YVYU8_2X8, | ||
269 | .fmt = { | ||
270 | .fourcc = V4L2_PIX_FMT_YVYU, | ||
271 | .name = "YVYU", | ||
272 | .bits_per_sample = 8, | ||
273 | .packing = PXA_MBUS_PACKING_2X8_PADHI, | ||
274 | .order = PXA_MBUS_ORDER_LE, | ||
275 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
276 | }, | ||
277 | }, { | ||
278 | .code = MEDIA_BUS_FMT_UYVY8_2X8, | ||
279 | .fmt = { | ||
280 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
281 | .name = "UYVY", | ||
282 | .bits_per_sample = 8, | ||
283 | .packing = PXA_MBUS_PACKING_2X8_PADHI, | ||
284 | .order = PXA_MBUS_ORDER_LE, | ||
285 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
286 | }, | ||
287 | }, { | ||
288 | .code = MEDIA_BUS_FMT_VYUY8_2X8, | ||
289 | .fmt = { | ||
290 | .fourcc = V4L2_PIX_FMT_VYUY, | ||
291 | .name = "VYUY", | ||
292 | .bits_per_sample = 8, | ||
293 | .packing = PXA_MBUS_PACKING_2X8_PADHI, | ||
294 | .order = PXA_MBUS_ORDER_LE, | ||
295 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
296 | }, | ||
297 | }, { | ||
298 | .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, | ||
299 | .fmt = { | ||
300 | .fourcc = V4L2_PIX_FMT_RGB555, | ||
301 | .name = "RGB555", | ||
302 | .bits_per_sample = 8, | ||
303 | .packing = PXA_MBUS_PACKING_2X8_PADHI, | ||
304 | .order = PXA_MBUS_ORDER_LE, | ||
305 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
306 | }, | ||
307 | }, { | ||
308 | .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, | ||
309 | .fmt = { | ||
310 | .fourcc = V4L2_PIX_FMT_RGB555X, | ||
311 | .name = "RGB555X", | ||
312 | .bits_per_sample = 8, | ||
313 | .packing = PXA_MBUS_PACKING_2X8_PADHI, | ||
314 | .order = PXA_MBUS_ORDER_BE, | ||
315 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
316 | }, | ||
317 | }, { | ||
318 | .code = MEDIA_BUS_FMT_RGB565_2X8_LE, | ||
319 | .fmt = { | ||
320 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
321 | .name = "RGB565", | ||
322 | .bits_per_sample = 8, | ||
323 | .packing = PXA_MBUS_PACKING_2X8_PADHI, | ||
324 | .order = PXA_MBUS_ORDER_LE, | ||
325 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
326 | }, | ||
327 | }, { | ||
328 | .code = MEDIA_BUS_FMT_RGB565_2X8_BE, | ||
329 | .fmt = { | ||
330 | .fourcc = V4L2_PIX_FMT_RGB565X, | ||
331 | .name = "RGB565X", | ||
332 | .bits_per_sample = 8, | ||
333 | .packing = PXA_MBUS_PACKING_2X8_PADHI, | ||
334 | .order = PXA_MBUS_ORDER_BE, | ||
335 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
336 | }, | ||
337 | }, { | ||
338 | .code = MEDIA_BUS_FMT_SBGGR8_1X8, | ||
339 | .fmt = { | ||
340 | .fourcc = V4L2_PIX_FMT_SBGGR8, | ||
341 | .name = "Bayer 8 BGGR", | ||
342 | .bits_per_sample = 8, | ||
343 | .packing = PXA_MBUS_PACKING_NONE, | ||
344 | .order = PXA_MBUS_ORDER_LE, | ||
345 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
346 | }, | ||
347 | }, { | ||
348 | .code = MEDIA_BUS_FMT_SBGGR10_1X10, | ||
349 | .fmt = { | ||
350 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
351 | .name = "Bayer 10 BGGR", | ||
352 | .bits_per_sample = 10, | ||
353 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
354 | .order = PXA_MBUS_ORDER_LE, | ||
355 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
356 | }, | ||
357 | }, { | ||
358 | .code = MEDIA_BUS_FMT_Y8_1X8, | ||
359 | .fmt = { | ||
360 | .fourcc = V4L2_PIX_FMT_GREY, | ||
361 | .name = "Grey", | ||
362 | .bits_per_sample = 8, | ||
363 | .packing = PXA_MBUS_PACKING_NONE, | ||
364 | .order = PXA_MBUS_ORDER_LE, | ||
365 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
366 | }, | ||
367 | }, { | ||
368 | .code = MEDIA_BUS_FMT_Y10_1X10, | ||
369 | .fmt = { | ||
370 | .fourcc = V4L2_PIX_FMT_Y10, | ||
371 | .name = "Grey 10bit", | ||
372 | .bits_per_sample = 10, | ||
373 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
374 | .order = PXA_MBUS_ORDER_LE, | ||
375 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
376 | }, | ||
377 | }, { | ||
378 | .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, | ||
379 | .fmt = { | ||
380 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
381 | .name = "Bayer 10 BGGR", | ||
382 | .bits_per_sample = 8, | ||
383 | .packing = PXA_MBUS_PACKING_2X8_PADHI, | ||
384 | .order = PXA_MBUS_ORDER_LE, | ||
385 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
386 | }, | ||
387 | }, { | ||
388 | .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, | ||
389 | .fmt = { | ||
390 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
391 | .name = "Bayer 10 BGGR", | ||
392 | .bits_per_sample = 8, | ||
393 | .packing = PXA_MBUS_PACKING_2X8_PADHI, | ||
394 | .order = PXA_MBUS_ORDER_BE, | ||
395 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
396 | }, | ||
397 | }, { | ||
398 | .code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, | ||
399 | .fmt = { | ||
400 | .fourcc = V4L2_PIX_FMT_RGB444, | ||
401 | .name = "RGB444", | ||
402 | .bits_per_sample = 8, | ||
403 | .packing = PXA_MBUS_PACKING_2X8_PADHI, | ||
404 | .order = PXA_MBUS_ORDER_BE, | ||
405 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
406 | }, | ||
407 | }, { | ||
408 | .code = MEDIA_BUS_FMT_UYVY8_1X16, | ||
409 | .fmt = { | ||
410 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
411 | .name = "UYVY 16bit", | ||
412 | .bits_per_sample = 16, | ||
413 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
414 | .order = PXA_MBUS_ORDER_LE, | ||
415 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
416 | }, | ||
417 | }, { | ||
418 | .code = MEDIA_BUS_FMT_VYUY8_1X16, | ||
419 | .fmt = { | ||
420 | .fourcc = V4L2_PIX_FMT_VYUY, | ||
421 | .name = "VYUY 16bit", | ||
422 | .bits_per_sample = 16, | ||
423 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
424 | .order = PXA_MBUS_ORDER_LE, | ||
425 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
426 | }, | ||
427 | }, { | ||
428 | .code = MEDIA_BUS_FMT_YUYV8_1X16, | ||
429 | .fmt = { | ||
430 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
431 | .name = "YUYV 16bit", | ||
432 | .bits_per_sample = 16, | ||
433 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
434 | .order = PXA_MBUS_ORDER_LE, | ||
435 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
436 | }, | ||
437 | }, { | ||
438 | .code = MEDIA_BUS_FMT_YVYU8_1X16, | ||
439 | .fmt = { | ||
440 | .fourcc = V4L2_PIX_FMT_YVYU, | ||
441 | .name = "YVYU 16bit", | ||
442 | .bits_per_sample = 16, | ||
443 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
444 | .order = PXA_MBUS_ORDER_LE, | ||
445 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
446 | }, | ||
447 | }, { | ||
448 | .code = MEDIA_BUS_FMT_SGRBG8_1X8, | ||
449 | .fmt = { | ||
450 | .fourcc = V4L2_PIX_FMT_SGRBG8, | ||
451 | .name = "Bayer 8 GRBG", | ||
452 | .bits_per_sample = 8, | ||
453 | .packing = PXA_MBUS_PACKING_NONE, | ||
454 | .order = PXA_MBUS_ORDER_LE, | ||
455 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
456 | }, | ||
457 | }, { | ||
458 | .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, | ||
459 | .fmt = { | ||
460 | .fourcc = V4L2_PIX_FMT_SGRBG10DPCM8, | ||
461 | .name = "Bayer 10 BGGR DPCM 8", | ||
462 | .bits_per_sample = 8, | ||
463 | .packing = PXA_MBUS_PACKING_NONE, | ||
464 | .order = PXA_MBUS_ORDER_LE, | ||
465 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
466 | }, | ||
467 | }, { | ||
468 | .code = MEDIA_BUS_FMT_SGBRG10_1X10, | ||
469 | .fmt = { | ||
470 | .fourcc = V4L2_PIX_FMT_SGBRG10, | ||
471 | .name = "Bayer 10 GBRG", | ||
472 | .bits_per_sample = 10, | ||
473 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
474 | .order = PXA_MBUS_ORDER_LE, | ||
475 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
476 | }, | ||
477 | }, { | ||
478 | .code = MEDIA_BUS_FMT_SGRBG10_1X10, | ||
479 | .fmt = { | ||
480 | .fourcc = V4L2_PIX_FMT_SGRBG10, | ||
481 | .name = "Bayer 10 GRBG", | ||
482 | .bits_per_sample = 10, | ||
483 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
484 | .order = PXA_MBUS_ORDER_LE, | ||
485 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
486 | }, | ||
487 | }, { | ||
488 | .code = MEDIA_BUS_FMT_SRGGB10_1X10, | ||
489 | .fmt = { | ||
490 | .fourcc = V4L2_PIX_FMT_SRGGB10, | ||
491 | .name = "Bayer 10 RGGB", | ||
492 | .bits_per_sample = 10, | ||
493 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
494 | .order = PXA_MBUS_ORDER_LE, | ||
495 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
496 | }, | ||
497 | }, { | ||
498 | .code = MEDIA_BUS_FMT_SBGGR12_1X12, | ||
499 | .fmt = { | ||
500 | .fourcc = V4L2_PIX_FMT_SBGGR12, | ||
501 | .name = "Bayer 12 BGGR", | ||
502 | .bits_per_sample = 12, | ||
503 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
504 | .order = PXA_MBUS_ORDER_LE, | ||
505 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
506 | }, | ||
507 | }, { | ||
508 | .code = MEDIA_BUS_FMT_SGBRG12_1X12, | ||
509 | .fmt = { | ||
510 | .fourcc = V4L2_PIX_FMT_SGBRG12, | ||
511 | .name = "Bayer 12 GBRG", | ||
512 | .bits_per_sample = 12, | ||
513 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
514 | .order = PXA_MBUS_ORDER_LE, | ||
515 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
516 | }, | ||
517 | }, { | ||
518 | .code = MEDIA_BUS_FMT_SGRBG12_1X12, | ||
519 | .fmt = { | ||
520 | .fourcc = V4L2_PIX_FMT_SGRBG12, | ||
521 | .name = "Bayer 12 GRBG", | ||
522 | .bits_per_sample = 12, | ||
523 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
524 | .order = PXA_MBUS_ORDER_LE, | ||
525 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
526 | }, | ||
527 | }, { | ||
528 | .code = MEDIA_BUS_FMT_SRGGB12_1X12, | ||
529 | .fmt = { | ||
530 | .fourcc = V4L2_PIX_FMT_SRGGB12, | ||
531 | .name = "Bayer 12 RGGB", | ||
532 | .bits_per_sample = 12, | ||
533 | .packing = PXA_MBUS_PACKING_EXTEND16, | ||
534 | .order = PXA_MBUS_ORDER_LE, | ||
535 | .layout = PXA_MBUS_LAYOUT_PACKED, | ||
536 | }, | ||
537 | }, | ||
538 | }; | ||
539 | |||
540 | static s32 pxa_mbus_bytes_per_line(u32 width, const struct pxa_mbus_pixelfmt *mf) | ||
541 | { | ||
542 | if (mf->layout != PXA_MBUS_LAYOUT_PACKED) | ||
543 | return width * mf->bits_per_sample / 8; | ||
544 | |||
545 | switch (mf->packing) { | ||
546 | case PXA_MBUS_PACKING_NONE: | ||
547 | return width * mf->bits_per_sample / 8; | ||
548 | case PXA_MBUS_PACKING_2X8_PADHI: | ||
549 | case PXA_MBUS_PACKING_EXTEND16: | ||
550 | return width * 2; | ||
551 | } | ||
552 | return -EINVAL; | ||
553 | } | ||
554 | |||
555 | static s32 pxa_mbus_image_size(const struct pxa_mbus_pixelfmt *mf, | ||
556 | u32 bytes_per_line, u32 height) | ||
557 | { | ||
558 | switch (mf->packing) { | ||
559 | case PXA_MBUS_PACKING_2X8_PADHI: | ||
560 | return bytes_per_line * height * 2; | ||
561 | default: | ||
562 | return -EINVAL; | ||
563 | } | ||
564 | } | ||
565 | |||
566 | static const struct pxa_mbus_pixelfmt *pxa_mbus_find_fmtdesc( | ||
567 | u32 code, | ||
568 | const struct pxa_mbus_lookup *lookup, | ||
569 | int n) | ||
570 | { | ||
571 | int i; | ||
572 | |||
573 | for (i = 0; i < n; i++) | ||
574 | if (lookup[i].code == code) | ||
575 | return &lookup[i].fmt; | ||
576 | |||
577 | return NULL; | ||
578 | } | ||
579 | |||
580 | static const struct pxa_mbus_pixelfmt *pxa_mbus_get_fmtdesc( | ||
581 | u32 code) | ||
582 | { | ||
583 | return pxa_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt)); | ||
584 | } | ||
585 | |||
586 | static unsigned int pxa_mbus_config_compatible(const struct v4l2_mbus_config *cfg, | ||
587 | unsigned int flags) | ||
588 | { | ||
589 | unsigned long common_flags; | ||
590 | bool hsync = true, vsync = true, pclk, data, mode; | ||
591 | bool mipi_lanes, mipi_clock; | ||
592 | |||
593 | common_flags = cfg->flags & flags; | ||
594 | |||
595 | switch (cfg->type) { | ||
596 | case V4L2_MBUS_PARALLEL: | ||
597 | hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
598 | V4L2_MBUS_HSYNC_ACTIVE_LOW); | ||
599 | vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
600 | V4L2_MBUS_VSYNC_ACTIVE_LOW); | ||
601 | /* fall through */ | ||
602 | case V4L2_MBUS_BT656: | ||
603 | pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
604 | V4L2_MBUS_PCLK_SAMPLE_FALLING); | ||
605 | data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH | | ||
606 | V4L2_MBUS_DATA_ACTIVE_LOW); | ||
607 | mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE); | ||
608 | return (!hsync || !vsync || !pclk || !data || !mode) ? | ||
609 | 0 : common_flags; | ||
610 | case V4L2_MBUS_CSI2: | ||
611 | mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES; | ||
612 | mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | | ||
613 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK); | ||
614 | return (!mipi_lanes || !mipi_clock) ? 0 : common_flags; | ||
615 | } | ||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | /** | ||
620 | * struct soc_camera_format_xlate - match between host and sensor formats | ||
621 | * @code: code of a sensor provided format | ||
622 | * @host_fmt: host format after host translation from code | ||
623 | * | ||
624 | * Host and sensor translation structure. Used in table of host and sensor | ||
625 | * formats matchings in soc_camera_device. A host can override the generic list | ||
626 | * generation by implementing get_formats(), and use it for format checks and | ||
627 | * format setup. | ||
628 | */ | ||
629 | struct soc_camera_format_xlate { | ||
630 | u32 code; | ||
631 | const struct pxa_mbus_pixelfmt *host_fmt; | ||
632 | }; | ||
633 | |||
171 | /* | 634 | /* |
172 | * Structures | 635 | * Structures |
173 | */ | 636 | */ |
@@ -180,19 +643,33 @@ enum pxa_camera_active_dma { | |||
180 | /* buffer for one video frame */ | 643 | /* buffer for one video frame */ |
181 | struct pxa_buffer { | 644 | struct pxa_buffer { |
182 | /* common v4l buffer stuff -- must be first */ | 645 | /* common v4l buffer stuff -- must be first */ |
183 | struct videobuf_buffer vb; | 646 | struct vb2_v4l2_buffer vbuf; |
647 | struct list_head queue; | ||
184 | u32 code; | 648 | u32 code; |
649 | int nb_planes; | ||
185 | /* our descriptor lists for Y, U and V channels */ | 650 | /* our descriptor lists for Y, U and V channels */ |
186 | struct dma_async_tx_descriptor *descs[3]; | 651 | struct dma_async_tx_descriptor *descs[3]; |
187 | dma_cookie_t cookie[3]; | 652 | dma_cookie_t cookie[3]; |
188 | struct scatterlist *sg[3]; | 653 | struct scatterlist *sg[3]; |
189 | int sg_len[3]; | 654 | int sg_len[3]; |
655 | size_t plane_sizes[3]; | ||
190 | int inwork; | 656 | int inwork; |
191 | enum pxa_camera_active_dma active_dma; | 657 | enum pxa_camera_active_dma active_dma; |
192 | }; | 658 | }; |
193 | 659 | ||
194 | struct pxa_camera_dev { | 660 | struct pxa_camera_dev { |
195 | struct soc_camera_host soc_host; | 661 | struct v4l2_device v4l2_dev; |
662 | struct video_device vdev; | ||
663 | struct v4l2_async_notifier notifier; | ||
664 | struct vb2_queue vb2_vq; | ||
665 | struct v4l2_subdev *sensor; | ||
666 | struct soc_camera_format_xlate *user_formats; | ||
667 | const struct soc_camera_format_xlate *current_fmt; | ||
668 | struct v4l2_pix_format current_pix; | ||
669 | |||
670 | struct v4l2_async_subdev asd; | ||
671 | struct v4l2_async_subdev *asds[1]; | ||
672 | |||
196 | /* | 673 | /* |
197 | * PXA27x is only supposed to handle one camera on its Quick Capture | 674 | * PXA27x is only supposed to handle one camera on its Quick Capture |
198 | * interface. If anyone ever builds hardware to enable more than | 675 | * interface. If anyone ever builds hardware to enable more than |
@@ -212,11 +689,14 @@ struct pxa_camera_dev { | |||
212 | unsigned long ciclk; | 689 | unsigned long ciclk; |
213 | unsigned long mclk; | 690 | unsigned long mclk; |
214 | u32 mclk_divisor; | 691 | u32 mclk_divisor; |
692 | struct v4l2_clk *mclk_clk; | ||
215 | u16 width_flags; /* max 10 bits */ | 693 | u16 width_flags; /* max 10 bits */ |
216 | 694 | ||
217 | struct list_head capture; | 695 | struct list_head capture; |
218 | 696 | ||
219 | spinlock_t lock; | 697 | spinlock_t lock; |
698 | struct mutex mlock; | ||
699 | unsigned int buf_sequence; | ||
220 | 700 | ||
221 | struct pxa_buffer *active; | 701 | struct pxa_buffer *active; |
222 | struct tasklet_struct task_eof; | 702 | struct tasklet_struct task_eof; |
@@ -230,59 +710,90 @@ struct pxa_cam { | |||
230 | 710 | ||
231 | static const char *pxa_cam_driver_description = "PXA_Camera"; | 711 | static const char *pxa_cam_driver_description = "PXA_Camera"; |
232 | 712 | ||
233 | static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ | ||
234 | |||
235 | /* | 713 | /* |
236 | * Videobuf operations | 714 | * Format translation functions |
237 | */ | 715 | */ |
238 | static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | 716 | static const struct soc_camera_format_xlate |
239 | unsigned int *size) | 717 | *pxa_mbus_xlate_by_fourcc(struct soc_camera_format_xlate *user_formats, |
718 | unsigned int fourcc) | ||
240 | { | 719 | { |
241 | struct soc_camera_device *icd = vq->priv_data; | 720 | unsigned int i; |
242 | 721 | ||
243 | dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size); | 722 | for (i = 0; user_formats[i].code; i++) |
244 | 723 | if (user_formats[i].host_fmt->fourcc == fourcc) | |
245 | *size = icd->sizeimage; | 724 | return user_formats + i; |
246 | 725 | return NULL; | |
247 | if (0 == *count) | ||
248 | *count = 32; | ||
249 | if (*size * *count > vid_limit * 1024 * 1024) | ||
250 | *count = (vid_limit * 1024 * 1024) / *size; | ||
251 | |||
252 | return 0; | ||
253 | } | 726 | } |
254 | 727 | ||
255 | static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) | 728 | static struct soc_camera_format_xlate *pxa_mbus_build_fmts_xlate( |
729 | struct v4l2_device *v4l2_dev, struct v4l2_subdev *subdev, | ||
730 | int (*get_formats)(struct v4l2_device *, unsigned int, | ||
731 | struct soc_camera_format_xlate *xlate)) | ||
256 | { | 732 | { |
257 | struct soc_camera_device *icd = vq->priv_data; | 733 | unsigned int i, fmts = 0, raw_fmts = 0; |
258 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | 734 | int ret; |
259 | int i; | 735 | struct v4l2_subdev_mbus_code_enum code = { |
260 | 736 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | |
261 | BUG_ON(in_interrupt()); | 737 | }; |
738 | struct soc_camera_format_xlate *user_formats; | ||
262 | 739 | ||
263 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 740 | while (!v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &code)) { |
264 | &buf->vb, buf->vb.baddr, buf->vb.bsize); | 741 | raw_fmts++; |
742 | code.index++; | ||
743 | } | ||
265 | 744 | ||
266 | /* | 745 | /* |
267 | * This waits until this buffer is out of danger, i.e., until it is no | 746 | * First pass - only count formats this host-sensor |
268 | * longer in STATE_QUEUED or STATE_ACTIVE | 747 | * configuration can provide |
269 | */ | 748 | */ |
270 | videobuf_waiton(vq, &buf->vb, 0, 0); | 749 | for (i = 0; i < raw_fmts; i++) { |
750 | ret = get_formats(v4l2_dev, i, NULL); | ||
751 | if (ret < 0) | ||
752 | return ERR_PTR(ret); | ||
753 | fmts += ret; | ||
754 | } | ||
271 | 755 | ||
272 | for (i = 0; i < 3 && buf->descs[i]; i++) { | 756 | if (!fmts) |
273 | dmaengine_desc_free(buf->descs[i]); | 757 | return ERR_PTR(-ENXIO); |
274 | kfree(buf->sg[i]); | 758 | |
275 | buf->descs[i] = NULL; | 759 | user_formats = kcalloc(fmts + 1, sizeof(*user_formats), GFP_KERNEL); |
276 | buf->sg[i] = NULL; | 760 | if (!user_formats) |
277 | buf->sg_len[i] = 0; | 761 | return ERR_PTR(-ENOMEM); |
762 | |||
763 | /* Second pass - actually fill data formats */ | ||
764 | fmts = 0; | ||
765 | for (i = 0; i < raw_fmts; i++) { | ||
766 | ret = get_formats(v4l2_dev, i, user_formats + fmts); | ||
767 | if (ret < 0) | ||
768 | goto egfmt; | ||
769 | fmts += ret; | ||
278 | } | 770 | } |
279 | videobuf_dma_unmap(vq->dev, dma); | 771 | user_formats[fmts].code = 0; |
280 | videobuf_dma_free(dma); | ||
281 | 772 | ||
282 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | 773 | return user_formats; |
774 | egfmt: | ||
775 | kfree(user_formats); | ||
776 | return ERR_PTR(ret); | ||
777 | } | ||
283 | 778 | ||
284 | dev_dbg(icd->parent, "%s end (vb=0x%p) 0x%08lx %d\n", __func__, | 779 | /* |
285 | &buf->vb, buf->vb.baddr, buf->vb.bsize); | 780 | * Videobuf operations |
781 | */ | ||
782 | static struct pxa_buffer *vb2_to_pxa_buffer(struct vb2_buffer *vb) | ||
783 | { | ||
784 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
785 | |||
786 | return container_of(vbuf, struct pxa_buffer, vbuf); | ||
787 | } | ||
788 | |||
789 | static struct device *pcdev_to_dev(struct pxa_camera_dev *pcdev) | ||
790 | { | ||
791 | return pcdev->v4l2_dev.dev; | ||
792 | } | ||
793 | |||
794 | static struct pxa_camera_dev *v4l2_dev_to_pcdev(struct v4l2_device *v4l2_dev) | ||
795 | { | ||
796 | return container_of(v4l2_dev, struct pxa_camera_dev, v4l2_dev); | ||
286 | } | 797 | } |
287 | 798 | ||
288 | static void pxa_camera_dma_irq(struct pxa_camera_dev *pcdev, | 799 | static void pxa_camera_dma_irq(struct pxa_camera_dev *pcdev, |
@@ -312,31 +823,26 @@ static void pxa_camera_dma_irq_v(void *data) | |||
312 | /** | 823 | /** |
313 | * pxa_init_dma_channel - init dma descriptors | 824 | * pxa_init_dma_channel - init dma descriptors |
314 | * @pcdev: pxa camera device | 825 | * @pcdev: pxa camera device |
315 | * @buf: pxa buffer to find pxa dma channel | 826 | * @vb: videobuffer2 buffer |
316 | * @dma: dma video buffer | 827 | * @dma: dma video buffer |
317 | * @channel: dma channel (0 => 'Y', 1 => 'U', 2 => 'V') | 828 | * @channel: dma channel (0 => 'Y', 1 => 'U', 2 => 'V') |
318 | * @cibr: camera Receive Buffer Register | 829 | * @cibr: camera Receive Buffer Register |
319 | * @size: bytes to transfer | ||
320 | * @offset: offset in videobuffer of the first byte to transfer | ||
321 | * | 830 | * |
322 | * Prepares the pxa dma descriptors to transfer one camera channel. | 831 | * Prepares the pxa dma descriptors to transfer one camera channel. |
323 | * | 832 | * |
324 | * Returns 0 if success or -ENOMEM if no memory is available | 833 | * Returns 0 if success or -ENOMEM if no memory is available |
325 | */ | 834 | */ |
326 | static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, | 835 | static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, |
327 | struct pxa_buffer *buf, | 836 | struct pxa_buffer *buf, int channel, |
328 | struct videobuf_dmabuf *dma, int channel, | 837 | struct scatterlist *sg, int sglen) |
329 | int cibr, int size, int offset) | ||
330 | { | 838 | { |
331 | struct dma_chan *dma_chan = pcdev->dma_chans[channel]; | 839 | struct dma_chan *dma_chan = pcdev->dma_chans[channel]; |
332 | struct scatterlist *sg = buf->sg[channel]; | ||
333 | int sglen = buf->sg_len[channel]; | ||
334 | struct dma_async_tx_descriptor *tx; | 840 | struct dma_async_tx_descriptor *tx; |
335 | 841 | ||
336 | tx = dmaengine_prep_slave_sg(dma_chan, sg, sglen, DMA_DEV_TO_MEM, | 842 | tx = dmaengine_prep_slave_sg(dma_chan, sg, sglen, DMA_DEV_TO_MEM, |
337 | DMA_PREP_INTERRUPT | DMA_CTRL_REUSE); | 843 | DMA_PREP_INTERRUPT | DMA_CTRL_REUSE); |
338 | if (!tx) { | 844 | if (!tx) { |
339 | dev_err(pcdev->soc_host.v4l2_dev.dev, | 845 | dev_err(pcdev_to_dev(pcdev), |
340 | "dmaengine_prep_slave_sg failed\n"); | 846 | "dmaengine_prep_slave_sg failed\n"); |
341 | goto fail; | 847 | goto fail; |
342 | } | 848 | } |
@@ -357,11 +863,9 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, | |||
357 | buf->descs[channel] = tx; | 863 | buf->descs[channel] = tx; |
358 | return 0; | 864 | return 0; |
359 | fail: | 865 | fail: |
360 | kfree(sg); | 866 | dev_dbg(pcdev_to_dev(pcdev), |
361 | 867 | "%s (vb=%p) dma_tx=%p\n", | |
362 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, | 868 | __func__, buf, tx); |
363 | "%s (vb=0x%p) dma_tx=%p\n", | ||
364 | __func__, &buf->vb, tx); | ||
365 | 869 | ||
366 | return -ENOMEM; | 870 | return -ENOMEM; |
367 | } | 871 | } |
@@ -370,133 +874,10 @@ static void pxa_videobuf_set_actdma(struct pxa_camera_dev *pcdev, | |||
370 | struct pxa_buffer *buf) | 874 | struct pxa_buffer *buf) |
371 | { | 875 | { |
372 | buf->active_dma = DMA_Y; | 876 | buf->active_dma = DMA_Y; |
373 | if (pcdev->channels == 3) | 877 | if (buf->nb_planes == 3) |
374 | buf->active_dma |= DMA_U | DMA_V; | 878 | buf->active_dma |= DMA_U | DMA_V; |
375 | } | 879 | } |
376 | 880 | ||
377 | /* | ||
378 | * Please check the DMA prepared buffer structure in : | ||
379 | * Documentation/video4linux/pxa_camera.txt | ||
380 | * Please check also in pxa_camera_check_link_miss() to understand why DMA chain | ||
381 | * modification while DMA chain is running will work anyway. | ||
382 | */ | ||
383 | static int pxa_videobuf_prepare(struct videobuf_queue *vq, | ||
384 | struct videobuf_buffer *vb, enum v4l2_field field) | ||
385 | { | ||
386 | struct soc_camera_device *icd = vq->priv_data; | ||
387 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
388 | struct pxa_camera_dev *pcdev = ici->priv; | ||
389 | struct device *dev = pcdev->soc_host.v4l2_dev.dev; | ||
390 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | ||
391 | int ret; | ||
392 | int size_y, size_u = 0, size_v = 0; | ||
393 | size_t sizes[3]; | ||
394 | |||
395 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
396 | vb, vb->baddr, vb->bsize); | ||
397 | |||
398 | /* Added list head initialization on alloc */ | ||
399 | WARN_ON(!list_empty(&vb->queue)); | ||
400 | |||
401 | #ifdef DEBUG | ||
402 | /* | ||
403 | * This can be useful if you want to see if we actually fill | ||
404 | * the buffer with something | ||
405 | */ | ||
406 | memset((void *)vb->baddr, 0xaa, vb->bsize); | ||
407 | #endif | ||
408 | |||
409 | BUG_ON(NULL == icd->current_fmt); | ||
410 | |||
411 | /* | ||
412 | * I think, in buf_prepare you only have to protect global data, | ||
413 | * the actual buffer is yours | ||
414 | */ | ||
415 | buf->inwork = 1; | ||
416 | |||
417 | if (buf->code != icd->current_fmt->code || | ||
418 | vb->width != icd->user_width || | ||
419 | vb->height != icd->user_height || | ||
420 | vb->field != field) { | ||
421 | buf->code = icd->current_fmt->code; | ||
422 | vb->width = icd->user_width; | ||
423 | vb->height = icd->user_height; | ||
424 | vb->field = field; | ||
425 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
426 | } | ||
427 | |||
428 | vb->size = icd->sizeimage; | ||
429 | if (0 != vb->baddr && vb->bsize < vb->size) { | ||
430 | ret = -EINVAL; | ||
431 | goto out; | ||
432 | } | ||
433 | |||
434 | if (vb->state == VIDEOBUF_NEEDS_INIT) { | ||
435 | int size = vb->size; | ||
436 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | ||
437 | |||
438 | ret = videobuf_iolock(vq, vb, NULL); | ||
439 | if (ret) | ||
440 | goto out; | ||
441 | |||
442 | if (pcdev->channels == 3) { | ||
443 | size_y = size / 2; | ||
444 | size_u = size_v = size / 4; | ||
445 | } else { | ||
446 | size_y = size; | ||
447 | } | ||
448 | |||
449 | sizes[0] = size_y; | ||
450 | sizes[1] = size_u; | ||
451 | sizes[2] = size_v; | ||
452 | ret = sg_split(dma->sglist, dma->sglen, 0, pcdev->channels, | ||
453 | sizes, buf->sg, buf->sg_len, GFP_KERNEL); | ||
454 | if (ret < 0) { | ||
455 | dev_err(dev, "sg_split failed: %d\n", ret); | ||
456 | goto fail; | ||
457 | } | ||
458 | |||
459 | /* init DMA for Y channel */ | ||
460 | ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, | ||
461 | size_y, 0); | ||
462 | if (ret) { | ||
463 | dev_err(dev, "DMA initialization for Y/RGB failed\n"); | ||
464 | goto fail; | ||
465 | } | ||
466 | |||
467 | /* init DMA for U channel */ | ||
468 | if (size_u) | ||
469 | ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1, | ||
470 | size_u, size_y); | ||
471 | if (ret) { | ||
472 | dev_err(dev, "DMA initialization for U failed\n"); | ||
473 | goto fail; | ||
474 | } | ||
475 | |||
476 | /* init DMA for V channel */ | ||
477 | if (size_v) | ||
478 | ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2, | ||
479 | size_v, size_y + size_u); | ||
480 | if (ret) { | ||
481 | dev_err(dev, "DMA initialization for V failed\n"); | ||
482 | goto fail; | ||
483 | } | ||
484 | |||
485 | vb->state = VIDEOBUF_PREPARED; | ||
486 | } | ||
487 | |||
488 | buf->inwork = 0; | ||
489 | pxa_videobuf_set_actdma(pcdev, buf); | ||
490 | |||
491 | return 0; | ||
492 | |||
493 | fail: | ||
494 | free_buffer(vq, buf); | ||
495 | out: | ||
496 | buf->inwork = 0; | ||
497 | return ret; | ||
498 | } | ||
499 | |||
500 | /** | 881 | /** |
501 | * pxa_dma_start_channels - start DMA channel for active buffer | 882 | * pxa_dma_start_channels - start DMA channel for active buffer |
502 | * @pcdev: pxa camera device | 883 | * @pcdev: pxa camera device |
@@ -507,12 +888,9 @@ out: | |||
507 | static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev) | 888 | static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev) |
508 | { | 889 | { |
509 | int i; | 890 | int i; |
510 | struct pxa_buffer *active; | ||
511 | |||
512 | active = pcdev->active; | ||
513 | 891 | ||
514 | for (i = 0; i < pcdev->channels; i++) { | 892 | for (i = 0; i < pcdev->channels; i++) { |
515 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, | 893 | dev_dbg(pcdev_to_dev(pcdev), |
516 | "%s (channel=%d)\n", __func__, i); | 894 | "%s (channel=%d)\n", __func__, i); |
517 | dma_async_issue_pending(pcdev->dma_chans[i]); | 895 | dma_async_issue_pending(pcdev->dma_chans[i]); |
518 | } | 896 | } |
@@ -523,7 +901,7 @@ static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev) | |||
523 | int i; | 901 | int i; |
524 | 902 | ||
525 | for (i = 0; i < pcdev->channels; i++) { | 903 | for (i = 0; i < pcdev->channels; i++) { |
526 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, | 904 | dev_dbg(pcdev_to_dev(pcdev), |
527 | "%s (channel=%d)\n", __func__, i); | 905 | "%s (channel=%d)\n", __func__, i); |
528 | dmaengine_terminate_all(pcdev->dma_chans[i]); | 906 | dmaengine_terminate_all(pcdev->dma_chans[i]); |
529 | } | 907 | } |
@@ -536,7 +914,7 @@ static void pxa_dma_add_tail_buf(struct pxa_camera_dev *pcdev, | |||
536 | 914 | ||
537 | for (i = 0; i < pcdev->channels; i++) { | 915 | for (i = 0; i < pcdev->channels; i++) { |
538 | buf->cookie[i] = dmaengine_submit(buf->descs[i]); | 916 | buf->cookie[i] = dmaengine_submit(buf->descs[i]); |
539 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, | 917 | dev_dbg(pcdev_to_dev(pcdev), |
540 | "%s (channel=%d) : submit vb=%p cookie=%d\n", | 918 | "%s (channel=%d) : submit vb=%p cookie=%d\n", |
541 | __func__, i, buf, buf->descs[i]->cookie); | 919 | __func__, i, buf, buf->descs[i]->cookie); |
542 | } | 920 | } |
@@ -554,7 +932,7 @@ static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev) | |||
554 | { | 932 | { |
555 | unsigned long cicr0; | 933 | unsigned long cicr0; |
556 | 934 | ||
557 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__); | 935 | dev_dbg(pcdev_to_dev(pcdev), "%s\n", __func__); |
558 | __raw_writel(__raw_readl(pcdev->base + CISR), pcdev->base + CISR); | 936 | __raw_writel(__raw_readl(pcdev->base + CISR), pcdev->base + CISR); |
559 | /* Enable End-Of-Frame Interrupt */ | 937 | /* Enable End-Of-Frame Interrupt */ |
560 | cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB; | 938 | cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB; |
@@ -572,72 +950,24 @@ static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev) | |||
572 | __raw_writel(cicr0, pcdev->base + CICR0); | 950 | __raw_writel(cicr0, pcdev->base + CICR0); |
573 | 951 | ||
574 | pcdev->active = NULL; | 952 | pcdev->active = NULL; |
575 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__); | 953 | dev_dbg(pcdev_to_dev(pcdev), "%s\n", __func__); |
576 | } | ||
577 | |||
578 | /* Called under spinlock_irqsave(&pcdev->lock, ...) */ | ||
579 | static void pxa_videobuf_queue(struct videobuf_queue *vq, | ||
580 | struct videobuf_buffer *vb) | ||
581 | { | ||
582 | struct soc_camera_device *icd = vq->priv_data; | ||
583 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
584 | struct pxa_camera_dev *pcdev = ici->priv; | ||
585 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | ||
586 | |||
587 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d active=%p\n", | ||
588 | __func__, vb, vb->baddr, vb->bsize, pcdev->active); | ||
589 | |||
590 | list_add_tail(&vb->queue, &pcdev->capture); | ||
591 | |||
592 | vb->state = VIDEOBUF_ACTIVE; | ||
593 | pxa_dma_add_tail_buf(pcdev, buf); | ||
594 | |||
595 | if (!pcdev->active) | ||
596 | pxa_camera_start_capture(pcdev); | ||
597 | } | ||
598 | |||
599 | static void pxa_videobuf_release(struct videobuf_queue *vq, | ||
600 | struct videobuf_buffer *vb) | ||
601 | { | ||
602 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | ||
603 | #ifdef DEBUG | ||
604 | struct soc_camera_device *icd = vq->priv_data; | ||
605 | struct device *dev = icd->parent; | ||
606 | |||
607 | dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
608 | vb, vb->baddr, vb->bsize); | ||
609 | |||
610 | switch (vb->state) { | ||
611 | case VIDEOBUF_ACTIVE: | ||
612 | dev_dbg(dev, "%s (active)\n", __func__); | ||
613 | break; | ||
614 | case VIDEOBUF_QUEUED: | ||
615 | dev_dbg(dev, "%s (queued)\n", __func__); | ||
616 | break; | ||
617 | case VIDEOBUF_PREPARED: | ||
618 | dev_dbg(dev, "%s (prepared)\n", __func__); | ||
619 | break; | ||
620 | default: | ||
621 | dev_dbg(dev, "%s (unknown)\n", __func__); | ||
622 | break; | ||
623 | } | ||
624 | #endif | ||
625 | |||
626 | free_buffer(vq, buf); | ||
627 | } | 954 | } |
628 | 955 | ||
629 | static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, | 956 | static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, |
630 | struct videobuf_buffer *vb, | 957 | struct pxa_buffer *buf, |
631 | struct pxa_buffer *buf) | 958 | enum vb2_buffer_state state) |
632 | { | 959 | { |
960 | struct vb2_buffer *vb = &buf->vbuf.vb2_buf; | ||
961 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
962 | |||
633 | /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ | 963 | /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ |
634 | list_del_init(&vb->queue); | 964 | list_del_init(&buf->queue); |
635 | vb->state = VIDEOBUF_DONE; | 965 | vb->timestamp = ktime_get_ns(); |
636 | v4l2_get_timestamp(&vb->ts); | 966 | vbuf->sequence = pcdev->buf_sequence++; |
637 | vb->field_count++; | 967 | vbuf->field = V4L2_FIELD_NONE; |
638 | wake_up(&vb->done); | 968 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); |
639 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s dequeud buffer (vb=0x%p)\n", | 969 | dev_dbg(pcdev_to_dev(pcdev), "%s dequeued buffer (buf=0x%p)\n", |
640 | __func__, vb); | 970 | __func__, buf); |
641 | 971 | ||
642 | if (list_empty(&pcdev->capture)) { | 972 | if (list_empty(&pcdev->capture)) { |
643 | pxa_camera_stop_capture(pcdev); | 973 | pxa_camera_stop_capture(pcdev); |
@@ -645,7 +975,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, | |||
645 | } | 975 | } |
646 | 976 | ||
647 | pcdev->active = list_entry(pcdev->capture.next, | 977 | pcdev->active = list_entry(pcdev->capture.next, |
648 | struct pxa_buffer, vb.queue); | 978 | struct pxa_buffer, queue); |
649 | } | 979 | } |
650 | 980 | ||
651 | /** | 981 | /** |
@@ -670,7 +1000,7 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev, | |||
670 | { | 1000 | { |
671 | bool is_dma_stopped = last_submitted != last_issued; | 1001 | bool is_dma_stopped = last_submitted != last_issued; |
672 | 1002 | ||
673 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, | 1003 | dev_dbg(pcdev_to_dev(pcdev), |
674 | "%s : top queued buffer=%p, is_dma_stopped=%d\n", | 1004 | "%s : top queued buffer=%p, is_dma_stopped=%d\n", |
675 | __func__, pcdev->active, is_dma_stopped); | 1005 | __func__, pcdev->active, is_dma_stopped); |
676 | 1006 | ||
@@ -681,19 +1011,17 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev, | |||
681 | static void pxa_camera_dma_irq(struct pxa_camera_dev *pcdev, | 1011 | static void pxa_camera_dma_irq(struct pxa_camera_dev *pcdev, |
682 | enum pxa_camera_active_dma act_dma) | 1012 | enum pxa_camera_active_dma act_dma) |
683 | { | 1013 | { |
684 | struct device *dev = pcdev->soc_host.v4l2_dev.dev; | ||
685 | struct pxa_buffer *buf, *last_buf; | 1014 | struct pxa_buffer *buf, *last_buf; |
686 | unsigned long flags; | 1015 | unsigned long flags; |
687 | u32 camera_status, overrun; | 1016 | u32 camera_status, overrun; |
688 | int chan; | 1017 | int chan; |
689 | struct videobuf_buffer *vb; | ||
690 | enum dma_status last_status; | 1018 | enum dma_status last_status; |
691 | dma_cookie_t last_issued; | 1019 | dma_cookie_t last_issued; |
692 | 1020 | ||
693 | spin_lock_irqsave(&pcdev->lock, flags); | 1021 | spin_lock_irqsave(&pcdev->lock, flags); |
694 | 1022 | ||
695 | camera_status = __raw_readl(pcdev->base + CISR); | 1023 | camera_status = __raw_readl(pcdev->base + CISR); |
696 | dev_dbg(dev, "camera dma irq, cisr=0x%x dma=%d\n", | 1024 | dev_dbg(pcdev_to_dev(pcdev), "camera dma irq, cisr=0x%x dma=%d\n", |
697 | camera_status, act_dma); | 1025 | camera_status, act_dma); |
698 | overrun = CISR_IFO_0; | 1026 | overrun = CISR_IFO_0; |
699 | if (pcdev->channels == 3) | 1027 | if (pcdev->channels == 3) |
@@ -714,9 +1042,8 @@ static void pxa_camera_dma_irq(struct pxa_camera_dev *pcdev, | |||
714 | if (!pcdev->active) | 1042 | if (!pcdev->active) |
715 | goto out; | 1043 | goto out; |
716 | 1044 | ||
717 | vb = &pcdev->active->vb; | 1045 | buf = pcdev->active; |
718 | buf = container_of(vb, struct pxa_buffer, vb); | 1046 | WARN_ON(buf->inwork || list_empty(&buf->queue)); |
719 | WARN_ON(buf->inwork || list_empty(&vb->queue)); | ||
720 | 1047 | ||
721 | /* | 1048 | /* |
722 | * It's normal if the last frame creates an overrun, as there | 1049 | * It's normal if the last frame creates an overrun, as there |
@@ -734,23 +1061,23 @@ static void pxa_camera_dma_irq(struct pxa_camera_dev *pcdev, | |||
734 | break; | 1061 | break; |
735 | } | 1062 | } |
736 | last_buf = list_entry(pcdev->capture.prev, | 1063 | last_buf = list_entry(pcdev->capture.prev, |
737 | struct pxa_buffer, vb.queue); | 1064 | struct pxa_buffer, queue); |
738 | last_status = dma_async_is_tx_complete(pcdev->dma_chans[chan], | 1065 | last_status = dma_async_is_tx_complete(pcdev->dma_chans[chan], |
739 | last_buf->cookie[chan], | 1066 | last_buf->cookie[chan], |
740 | NULL, &last_issued); | 1067 | NULL, &last_issued); |
741 | if (camera_status & overrun && | 1068 | if (camera_status & overrun && |
742 | last_status != DMA_COMPLETE) { | 1069 | last_status != DMA_COMPLETE) { |
743 | dev_dbg(dev, "FIFO overrun! CISR: %x\n", | 1070 | dev_dbg(pcdev_to_dev(pcdev), "FIFO overrun! CISR: %x\n", |
744 | camera_status); | 1071 | camera_status); |
745 | pxa_camera_stop_capture(pcdev); | 1072 | pxa_camera_stop_capture(pcdev); |
746 | list_for_each_entry(buf, &pcdev->capture, vb.queue) | 1073 | list_for_each_entry(buf, &pcdev->capture, queue) |
747 | pxa_dma_add_tail_buf(pcdev, buf); | 1074 | pxa_dma_add_tail_buf(pcdev, buf); |
748 | pxa_camera_start_capture(pcdev); | 1075 | pxa_camera_start_capture(pcdev); |
749 | goto out; | 1076 | goto out; |
750 | } | 1077 | } |
751 | buf->active_dma &= ~act_dma; | 1078 | buf->active_dma &= ~act_dma; |
752 | if (!buf->active_dma) { | 1079 | if (!buf->active_dma) { |
753 | pxa_camera_wakeup(pcdev, vb, buf); | 1080 | pxa_camera_wakeup(pcdev, buf, VB2_BUF_STATE_DONE); |
754 | pxa_camera_check_link_miss(pcdev, last_buf->cookie[chan], | 1081 | pxa_camera_check_link_miss(pcdev, last_buf->cookie[chan], |
755 | last_issued); | 1082 | last_issued); |
756 | } | 1083 | } |
@@ -759,33 +1086,10 @@ out: | |||
759 | spin_unlock_irqrestore(&pcdev->lock, flags); | 1086 | spin_unlock_irqrestore(&pcdev->lock, flags); |
760 | } | 1087 | } |
761 | 1088 | ||
762 | static struct videobuf_queue_ops pxa_videobuf_ops = { | ||
763 | .buf_setup = pxa_videobuf_setup, | ||
764 | .buf_prepare = pxa_videobuf_prepare, | ||
765 | .buf_queue = pxa_videobuf_queue, | ||
766 | .buf_release = pxa_videobuf_release, | ||
767 | }; | ||
768 | |||
769 | static void pxa_camera_init_videobuf(struct videobuf_queue *q, | ||
770 | struct soc_camera_device *icd) | ||
771 | { | ||
772 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
773 | struct pxa_camera_dev *pcdev = ici->priv; | ||
774 | |||
775 | /* | ||
776 | * We must pass NULL as dev pointer, then all pci_* dma operations | ||
777 | * transform to normal dma_* ones. | ||
778 | */ | ||
779 | videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock, | ||
780 | V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, | ||
781 | sizeof(struct pxa_buffer), icd, &ici->host_lock); | ||
782 | } | ||
783 | |||
784 | static u32 mclk_get_divisor(struct platform_device *pdev, | 1089 | static u32 mclk_get_divisor(struct platform_device *pdev, |
785 | struct pxa_camera_dev *pcdev) | 1090 | struct pxa_camera_dev *pcdev) |
786 | { | 1091 | { |
787 | unsigned long mclk = pcdev->mclk; | 1092 | unsigned long mclk = pcdev->mclk; |
788 | struct device *dev = &pdev->dev; | ||
789 | u32 div; | 1093 | u32 div; |
790 | unsigned long lcdclk; | 1094 | unsigned long lcdclk; |
791 | 1095 | ||
@@ -795,7 +1099,8 @@ static u32 mclk_get_divisor(struct platform_device *pdev, | |||
795 | /* mclk <= ciclk / 4 (27.4.2) */ | 1099 | /* mclk <= ciclk / 4 (27.4.2) */ |
796 | if (mclk > lcdclk / 4) { | 1100 | if (mclk > lcdclk / 4) { |
797 | mclk = lcdclk / 4; | 1101 | mclk = lcdclk / 4; |
798 | dev_warn(dev, "Limiting master clock to %lu\n", mclk); | 1102 | dev_warn(pcdev_to_dev(pcdev), |
1103 | "Limiting master clock to %lu\n", mclk); | ||
799 | } | 1104 | } |
800 | 1105 | ||
801 | /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */ | 1106 | /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */ |
@@ -805,7 +1110,7 @@ static u32 mclk_get_divisor(struct platform_device *pdev, | |||
805 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) | 1110 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) |
806 | pcdev->mclk = lcdclk / (2 * (div + 1)); | 1111 | pcdev->mclk = lcdclk / (2 * (div + 1)); |
807 | 1112 | ||
808 | dev_dbg(dev, "LCD clock %luHz, target freq %luHz, divisor %u\n", | 1113 | dev_dbg(pcdev_to_dev(pcdev), "LCD clock %luHz, target freq %luHz, divisor %u\n", |
809 | lcdclk, mclk, div); | 1114 | lcdclk, mclk, div); |
810 | 1115 | ||
811 | return div; | 1116 | return div; |
@@ -860,9 +1165,8 @@ static void pxa_camera_eof(unsigned long arg) | |||
860 | struct pxa_camera_dev *pcdev = (struct pxa_camera_dev *)arg; | 1165 | struct pxa_camera_dev *pcdev = (struct pxa_camera_dev *)arg; |
861 | unsigned long cifr; | 1166 | unsigned long cifr; |
862 | struct pxa_buffer *buf; | 1167 | struct pxa_buffer *buf; |
863 | struct videobuf_buffer *vb; | ||
864 | 1168 | ||
865 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, | 1169 | dev_dbg(pcdev_to_dev(pcdev), |
866 | "Camera interrupt status 0x%x\n", | 1170 | "Camera interrupt status 0x%x\n", |
867 | __raw_readl(pcdev->base + CISR)); | 1171 | __raw_readl(pcdev->base + CISR)); |
868 | 1172 | ||
@@ -871,9 +1175,8 @@ static void pxa_camera_eof(unsigned long arg) | |||
871 | __raw_writel(cifr, pcdev->base + CIFR); | 1175 | __raw_writel(cifr, pcdev->base + CIFR); |
872 | 1176 | ||
873 | pcdev->active = list_first_entry(&pcdev->capture, | 1177 | pcdev->active = list_first_entry(&pcdev->capture, |
874 | struct pxa_buffer, vb.queue); | 1178 | struct pxa_buffer, queue); |
875 | vb = &pcdev->active->vb; | 1179 | buf = pcdev->active; |
876 | buf = container_of(vb, struct pxa_buffer, vb); | ||
877 | pxa_videobuf_set_actdma(pcdev, buf); | 1180 | pxa_videobuf_set_actdma(pcdev, buf); |
878 | 1181 | ||
879 | pxa_dma_start_channels(pcdev); | 1182 | pxa_dma_start_channels(pcdev); |
@@ -885,7 +1188,7 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) | |||
885 | unsigned long status, cicr0; | 1188 | unsigned long status, cicr0; |
886 | 1189 | ||
887 | status = __raw_readl(pcdev->base + CISR); | 1190 | status = __raw_readl(pcdev->base + CISR); |
888 | dev_dbg(pcdev->soc_host.v4l2_dev.dev, | 1191 | dev_dbg(pcdev_to_dev(pcdev), |
889 | "Camera interrupt status 0x%lx\n", status); | 1192 | "Camera interrupt status 0x%lx\n", status); |
890 | 1193 | ||
891 | if (!status) | 1194 | if (!status) |
@@ -902,47 +1205,6 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) | |||
902 | return IRQ_HANDLED; | 1205 | return IRQ_HANDLED; |
903 | } | 1206 | } |
904 | 1207 | ||
905 | static int pxa_camera_add_device(struct soc_camera_device *icd) | ||
906 | { | ||
907 | dev_info(icd->parent, "PXA Camera driver attached to camera %d\n", | ||
908 | icd->devnum); | ||
909 | |||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | static void pxa_camera_remove_device(struct soc_camera_device *icd) | ||
914 | { | ||
915 | dev_info(icd->parent, "PXA Camera driver detached from camera %d\n", | ||
916 | icd->devnum); | ||
917 | } | ||
918 | |||
919 | /* | ||
920 | * The following two functions absolutely depend on the fact, that | ||
921 | * there can be only one camera on PXA quick capture interface | ||
922 | * Called with .host_lock held | ||
923 | */ | ||
924 | static int pxa_camera_clock_start(struct soc_camera_host *ici) | ||
925 | { | ||
926 | struct pxa_camera_dev *pcdev = ici->priv; | ||
927 | |||
928 | pxa_camera_activate(pcdev); | ||
929 | |||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | /* Called with .host_lock held */ | ||
934 | static void pxa_camera_clock_stop(struct soc_camera_host *ici) | ||
935 | { | ||
936 | struct pxa_camera_dev *pcdev = ici->priv; | ||
937 | |||
938 | /* disable capture, disable interrupts */ | ||
939 | __raw_writel(0x3ff, pcdev->base + CICR0); | ||
940 | |||
941 | /* Stop DMA engine */ | ||
942 | pxa_dma_stop_channels(pcdev); | ||
943 | pxa_camera_deactivate(pcdev); | ||
944 | } | ||
945 | |||
946 | static int test_platform_param(struct pxa_camera_dev *pcdev, | 1208 | static int test_platform_param(struct pxa_camera_dev *pcdev, |
947 | unsigned char buswidth, unsigned long *flags) | 1209 | unsigned char buswidth, unsigned long *flags) |
948 | { | 1210 | { |
@@ -968,15 +1230,12 @@ static int test_platform_param(struct pxa_camera_dev *pcdev, | |||
968 | return -EINVAL; | 1230 | return -EINVAL; |
969 | } | 1231 | } |
970 | 1232 | ||
971 | static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | 1233 | static void pxa_camera_setup_cicr(struct pxa_camera_dev *pcdev, |
972 | unsigned long flags, __u32 pixfmt) | 1234 | unsigned long flags, __u32 pixfmt) |
973 | { | 1235 | { |
974 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
975 | struct pxa_camera_dev *pcdev = ici->priv; | ||
976 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
977 | unsigned long dw, bpp; | 1236 | unsigned long dw, bpp; |
978 | u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0, y_skip_top; | 1237 | u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0, y_skip_top; |
979 | int ret = v4l2_subdev_call(sd, sensor, g_skip_top_lines, &y_skip_top); | 1238 | int ret = sensor_call(pcdev, sensor, g_skip_top_lines, &y_skip_top); |
980 | 1239 | ||
981 | if (ret < 0) | 1240 | if (ret < 0) |
982 | y_skip_top = 0; | 1241 | y_skip_top = 0; |
@@ -985,7 +1244,7 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
985 | * Datawidth is now guaranteed to be equal to one of the three values. | 1244 | * Datawidth is now guaranteed to be equal to one of the three values. |
986 | * We fix bit-per-pixel equal to data-width... | 1245 | * We fix bit-per-pixel equal to data-width... |
987 | */ | 1246 | */ |
988 | switch (icd->current_fmt->host_fmt->bits_per_sample) { | 1247 | switch (pcdev->current_fmt->host_fmt->bits_per_sample) { |
989 | case 10: | 1248 | case 10: |
990 | dw = 4; | 1249 | dw = 4; |
991 | bpp = 0x40; | 1250 | bpp = 0x40; |
@@ -1019,7 +1278,7 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1019 | if (cicr0 & CICR0_ENB) | 1278 | if (cicr0 & CICR0_ENB) |
1020 | __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0); | 1279 | __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0); |
1021 | 1280 | ||
1022 | cicr1 = CICR1_PPL_VAL(icd->user_width - 1) | bpp | dw; | 1281 | cicr1 = CICR1_PPL_VAL(pcdev->current_pix.width - 1) | bpp | dw; |
1023 | 1282 | ||
1024 | switch (pixfmt) { | 1283 | switch (pixfmt) { |
1025 | case V4L2_PIX_FMT_YUV422P: | 1284 | case V4L2_PIX_FMT_YUV422P: |
@@ -1048,7 +1307,7 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1048 | } | 1307 | } |
1049 | 1308 | ||
1050 | cicr2 = 0; | 1309 | cicr2 = 0; |
1051 | cicr3 = CICR3_LPF_VAL(icd->user_height - 1) | | 1310 | cicr3 = CICR3_LPF_VAL(pcdev->current_pix.height - 1) | |
1052 | CICR3_BFW_VAL(min((u32)255, y_skip_top)); | 1311 | CICR3_BFW_VAL(min((u32)255, y_skip_top)); |
1053 | cicr4 |= pcdev->mclk_divisor; | 1312 | cicr4 |= pcdev->mclk_divisor; |
1054 | 1313 | ||
@@ -1064,28 +1323,271 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1064 | __raw_writel(cicr0, pcdev->base + CICR0); | 1323 | __raw_writel(cicr0, pcdev->base + CICR0); |
1065 | } | 1324 | } |
1066 | 1325 | ||
1067 | static int pxa_camera_set_bus_param(struct soc_camera_device *icd) | 1326 | /* |
1327 | * Videobuf2 section | ||
1328 | */ | ||
1329 | static void pxa_buffer_cleanup(struct pxa_buffer *buf) | ||
1330 | { | ||
1331 | int i; | ||
1332 | |||
1333 | for (i = 0; i < 3 && buf->descs[i]; i++) { | ||
1334 | dmaengine_desc_free(buf->descs[i]); | ||
1335 | kfree(buf->sg[i]); | ||
1336 | buf->descs[i] = NULL; | ||
1337 | buf->sg[i] = NULL; | ||
1338 | buf->sg_len[i] = 0; | ||
1339 | buf->plane_sizes[i] = 0; | ||
1340 | } | ||
1341 | buf->nb_planes = 0; | ||
1342 | } | ||
1343 | |||
1344 | static int pxa_buffer_init(struct pxa_camera_dev *pcdev, | ||
1345 | struct pxa_buffer *buf) | ||
1346 | { | ||
1347 | struct vb2_buffer *vb = &buf->vbuf.vb2_buf; | ||
1348 | struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); | ||
1349 | int nb_channels = pcdev->channels; | ||
1350 | int i, ret = 0; | ||
1351 | unsigned long size = vb2_plane_size(vb, 0); | ||
1352 | |||
1353 | switch (nb_channels) { | ||
1354 | case 1: | ||
1355 | buf->plane_sizes[0] = size; | ||
1356 | break; | ||
1357 | case 3: | ||
1358 | buf->plane_sizes[0] = size / 2; | ||
1359 | buf->plane_sizes[1] = size / 4; | ||
1360 | buf->plane_sizes[2] = size / 4; | ||
1361 | break; | ||
1362 | default: | ||
1363 | return -EINVAL; | ||
1364 | }; | ||
1365 | buf->nb_planes = nb_channels; | ||
1366 | |||
1367 | ret = sg_split(sgt->sgl, sgt->nents, 0, nb_channels, | ||
1368 | buf->plane_sizes, buf->sg, buf->sg_len, GFP_KERNEL); | ||
1369 | if (ret < 0) { | ||
1370 | dev_err(pcdev_to_dev(pcdev), | ||
1371 | "sg_split failed: %d\n", ret); | ||
1372 | return ret; | ||
1373 | } | ||
1374 | for (i = 0; i < nb_channels; i++) { | ||
1375 | ret = pxa_init_dma_channel(pcdev, buf, i, | ||
1376 | buf->sg[i], buf->sg_len[i]); | ||
1377 | if (ret) { | ||
1378 | pxa_buffer_cleanup(buf); | ||
1379 | return ret; | ||
1380 | } | ||
1381 | } | ||
1382 | INIT_LIST_HEAD(&buf->queue); | ||
1383 | |||
1384 | return ret; | ||
1385 | } | ||
1386 | |||
1387 | static void pxac_vb2_cleanup(struct vb2_buffer *vb) | ||
1388 | { | ||
1389 | struct pxa_buffer *buf = vb2_to_pxa_buffer(vb); | ||
1390 | struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue); | ||
1391 | |||
1392 | dev_dbg(pcdev_to_dev(pcdev), | ||
1393 | "%s(vb=%p)\n", __func__, vb); | ||
1394 | pxa_buffer_cleanup(buf); | ||
1395 | } | ||
1396 | |||
1397 | static void pxac_vb2_queue(struct vb2_buffer *vb) | ||
1398 | { | ||
1399 | struct pxa_buffer *buf = vb2_to_pxa_buffer(vb); | ||
1400 | struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue); | ||
1401 | |||
1402 | dev_dbg(pcdev_to_dev(pcdev), | ||
1403 | "%s(vb=%p) nb_channels=%d size=%lu active=%p\n", | ||
1404 | __func__, vb, pcdev->channels, vb2_get_plane_payload(vb, 0), | ||
1405 | pcdev->active); | ||
1406 | |||
1407 | list_add_tail(&buf->queue, &pcdev->capture); | ||
1408 | |||
1409 | pxa_dma_add_tail_buf(pcdev, buf); | ||
1410 | } | ||
1411 | |||
1412 | /* | ||
1413 | * Please check the DMA prepared buffer structure in : | ||
1414 | * Documentation/video4linux/pxa_camera.txt | ||
1415 | * Please check also in pxa_camera_check_link_miss() to understand why DMA chain | ||
1416 | * modification while DMA chain is running will work anyway. | ||
1417 | */ | ||
1418 | static int pxac_vb2_prepare(struct vb2_buffer *vb) | ||
1419 | { | ||
1420 | struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue); | ||
1421 | struct pxa_buffer *buf = vb2_to_pxa_buffer(vb); | ||
1422 | int ret = 0; | ||
1423 | |||
1424 | switch (pcdev->channels) { | ||
1425 | case 1: | ||
1426 | case 3: | ||
1427 | vb2_set_plane_payload(vb, 0, pcdev->current_pix.sizeimage); | ||
1428 | break; | ||
1429 | default: | ||
1430 | return -EINVAL; | ||
1431 | } | ||
1432 | |||
1433 | dev_dbg(pcdev_to_dev(pcdev), | ||
1434 | "%s (vb=%p) nb_channels=%d size=%lu\n", | ||
1435 | __func__, vb, pcdev->channels, vb2_get_plane_payload(vb, 0)); | ||
1436 | |||
1437 | WARN_ON(!pcdev->current_fmt); | ||
1438 | |||
1439 | #ifdef DEBUG | ||
1440 | /* | ||
1441 | * This can be useful if you want to see if we actually fill | ||
1442 | * the buffer with something | ||
1443 | */ | ||
1444 | for (i = 0; i < vb->num_planes; i++) | ||
1445 | memset((void *)vb2_plane_vaddr(vb, i), | ||
1446 | 0xaa, vb2_get_plane_payload(vb, i)); | ||
1447 | #endif | ||
1448 | |||
1449 | /* | ||
1450 | * I think, in buf_prepare you only have to protect global data, | ||
1451 | * the actual buffer is yours | ||
1452 | */ | ||
1453 | buf->inwork = 0; | ||
1454 | pxa_videobuf_set_actdma(pcdev, buf); | ||
1455 | |||
1456 | return ret; | ||
1457 | } | ||
1458 | |||
1459 | static int pxac_vb2_init(struct vb2_buffer *vb) | ||
1460 | { | ||
1461 | struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue); | ||
1462 | struct pxa_buffer *buf = vb2_to_pxa_buffer(vb); | ||
1463 | |||
1464 | dev_dbg(pcdev_to_dev(pcdev), | ||
1465 | "%s(nb_channels=%d)\n", | ||
1466 | __func__, pcdev->channels); | ||
1467 | |||
1468 | return pxa_buffer_init(pcdev, buf); | ||
1469 | } | ||
1470 | |||
1471 | static int pxac_vb2_queue_setup(struct vb2_queue *vq, | ||
1472 | unsigned int *nbufs, | ||
1473 | unsigned int *num_planes, unsigned int sizes[], | ||
1474 | struct device *alloc_devs[]) | ||
1475 | { | ||
1476 | struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vq); | ||
1477 | int size = pcdev->current_pix.sizeimage; | ||
1478 | |||
1479 | dev_dbg(pcdev_to_dev(pcdev), | ||
1480 | "%s(vq=%p nbufs=%d num_planes=%d size=%d)\n", | ||
1481 | __func__, vq, *nbufs, *num_planes, size); | ||
1482 | /* | ||
1483 | * Called from VIDIOC_REQBUFS or in compatibility mode For YUV422P | ||
1484 | * format, even if there are 3 planes Y, U and V, we reply there is only | ||
1485 | * one plane, containing Y, U and V data, one after the other. | ||
1486 | */ | ||
1487 | if (*num_planes) | ||
1488 | return sizes[0] < size ? -EINVAL : 0; | ||
1489 | |||
1490 | *num_planes = 1; | ||
1491 | switch (pcdev->channels) { | ||
1492 | case 1: | ||
1493 | case 3: | ||
1494 | sizes[0] = size; | ||
1495 | break; | ||
1496 | default: | ||
1497 | return -EINVAL; | ||
1498 | } | ||
1499 | |||
1500 | if (!*nbufs) | ||
1501 | *nbufs = 1; | ||
1502 | |||
1503 | return 0; | ||
1504 | } | ||
1505 | |||
1506 | static int pxac_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
1507 | { | ||
1508 | struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vq); | ||
1509 | |||
1510 | dev_dbg(pcdev_to_dev(pcdev), "%s(count=%d) active=%p\n", | ||
1511 | __func__, count, pcdev->active); | ||
1512 | |||
1513 | pcdev->buf_sequence = 0; | ||
1514 | if (!pcdev->active) | ||
1515 | pxa_camera_start_capture(pcdev); | ||
1516 | |||
1517 | return 0; | ||
1518 | } | ||
1519 | |||
1520 | static void pxac_vb2_stop_streaming(struct vb2_queue *vq) | ||
1521 | { | ||
1522 | struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vq); | ||
1523 | struct pxa_buffer *buf, *tmp; | ||
1524 | |||
1525 | dev_dbg(pcdev_to_dev(pcdev), "%s active=%p\n", | ||
1526 | __func__, pcdev->active); | ||
1527 | pxa_camera_stop_capture(pcdev); | ||
1528 | |||
1529 | list_for_each_entry_safe(buf, tmp, &pcdev->capture, queue) | ||
1530 | pxa_camera_wakeup(pcdev, buf, VB2_BUF_STATE_ERROR); | ||
1531 | } | ||
1532 | |||
1533 | static struct vb2_ops pxac_vb2_ops = { | ||
1534 | .queue_setup = pxac_vb2_queue_setup, | ||
1535 | .buf_init = pxac_vb2_init, | ||
1536 | .buf_prepare = pxac_vb2_prepare, | ||
1537 | .buf_queue = pxac_vb2_queue, | ||
1538 | .buf_cleanup = pxac_vb2_cleanup, | ||
1539 | .start_streaming = pxac_vb2_start_streaming, | ||
1540 | .stop_streaming = pxac_vb2_stop_streaming, | ||
1541 | .wait_prepare = vb2_ops_wait_prepare, | ||
1542 | .wait_finish = vb2_ops_wait_finish, | ||
1543 | }; | ||
1544 | |||
1545 | static int pxa_camera_init_videobuf2(struct pxa_camera_dev *pcdev) | ||
1546 | { | ||
1547 | int ret; | ||
1548 | struct vb2_queue *vq = &pcdev->vb2_vq; | ||
1549 | |||
1550 | memset(vq, 0, sizeof(*vq)); | ||
1551 | vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1552 | vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; | ||
1553 | vq->drv_priv = pcdev; | ||
1554 | vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
1555 | vq->buf_struct_size = sizeof(struct pxa_buffer); | ||
1556 | vq->dev = pcdev->v4l2_dev.dev; | ||
1557 | |||
1558 | vq->ops = &pxac_vb2_ops; | ||
1559 | vq->mem_ops = &vb2_dma_sg_memops; | ||
1560 | vq->lock = &pcdev->mlock; | ||
1561 | |||
1562 | ret = vb2_queue_init(vq); | ||
1563 | dev_dbg(pcdev_to_dev(pcdev), | ||
1564 | "vb2_queue_init(vq=%p): %d\n", vq, ret); | ||
1565 | |||
1566 | return ret; | ||
1567 | } | ||
1568 | |||
1569 | /* | ||
1570 | * Video ioctls section | ||
1571 | */ | ||
1572 | static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev) | ||
1068 | { | 1573 | { |
1069 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1070 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1071 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1072 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | 1574 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
1073 | u32 pixfmt = icd->current_fmt->host_fmt->fourcc; | 1575 | u32 pixfmt = pcdev->current_fmt->host_fmt->fourcc; |
1074 | unsigned long bus_flags, common_flags; | 1576 | unsigned long bus_flags, common_flags; |
1075 | int ret; | 1577 | int ret; |
1076 | struct pxa_cam *cam = icd->host_priv; | ||
1077 | 1578 | ||
1078 | ret = test_platform_param(pcdev, icd->current_fmt->host_fmt->bits_per_sample, | 1579 | ret = test_platform_param(pcdev, |
1580 | pcdev->current_fmt->host_fmt->bits_per_sample, | ||
1079 | &bus_flags); | 1581 | &bus_flags); |
1080 | if (ret < 0) | 1582 | if (ret < 0) |
1081 | return ret; | 1583 | return ret; |
1082 | 1584 | ||
1083 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | 1585 | ret = sensor_call(pcdev, video, g_mbus_config, &cfg); |
1084 | if (!ret) { | 1586 | if (!ret) { |
1085 | common_flags = soc_mbus_config_compatible(&cfg, | 1587 | common_flags = pxa_mbus_config_compatible(&cfg, |
1086 | bus_flags); | 1588 | bus_flags); |
1087 | if (!common_flags) { | 1589 | if (!common_flags) { |
1088 | dev_warn(icd->parent, | 1590 | dev_warn(pcdev_to_dev(pcdev), |
1089 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | 1591 | "Flags incompatible: camera 0x%x, host 0x%lx\n", |
1090 | cfg.flags, bus_flags); | 1592 | cfg.flags, bus_flags); |
1091 | return -EINVAL; | 1593 | return -EINVAL; |
@@ -1124,26 +1626,22 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd) | |||
1124 | } | 1626 | } |
1125 | 1627 | ||
1126 | cfg.flags = common_flags; | 1628 | cfg.flags = common_flags; |
1127 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | 1629 | ret = sensor_call(pcdev, video, s_mbus_config, &cfg); |
1128 | if (ret < 0 && ret != -ENOIOCTLCMD) { | 1630 | if (ret < 0 && ret != -ENOIOCTLCMD) { |
1129 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | 1631 | dev_dbg(pcdev_to_dev(pcdev), |
1632 | "camera s_mbus_config(0x%lx) returned %d\n", | ||
1130 | common_flags, ret); | 1633 | common_flags, ret); |
1131 | return ret; | 1634 | return ret; |
1132 | } | 1635 | } |
1133 | 1636 | ||
1134 | cam->flags = common_flags; | 1637 | pxa_camera_setup_cicr(pcdev, common_flags, pixfmt); |
1135 | |||
1136 | pxa_camera_setup_cicr(icd, common_flags, pixfmt); | ||
1137 | 1638 | ||
1138 | return 0; | 1639 | return 0; |
1139 | } | 1640 | } |
1140 | 1641 | ||
1141 | static int pxa_camera_try_bus_param(struct soc_camera_device *icd, | 1642 | static int pxa_camera_try_bus_param(struct pxa_camera_dev *pcdev, |
1142 | unsigned char buswidth) | 1643 | unsigned char buswidth) |
1143 | { | 1644 | { |
1144 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1145 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1146 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1147 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | 1645 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
1148 | unsigned long bus_flags, common_flags; | 1646 | unsigned long bus_flags, common_flags; |
1149 | int ret = test_platform_param(pcdev, buswidth, &bus_flags); | 1647 | int ret = test_platform_param(pcdev, buswidth, &bus_flags); |
@@ -1151,12 +1649,12 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, | |||
1151 | if (ret < 0) | 1649 | if (ret < 0) |
1152 | return ret; | 1650 | return ret; |
1153 | 1651 | ||
1154 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | 1652 | ret = sensor_call(pcdev, video, g_mbus_config, &cfg); |
1155 | if (!ret) { | 1653 | if (!ret) { |
1156 | common_flags = soc_mbus_config_compatible(&cfg, | 1654 | common_flags = pxa_mbus_config_compatible(&cfg, |
1157 | bus_flags); | 1655 | bus_flags); |
1158 | if (!common_flags) { | 1656 | if (!common_flags) { |
1159 | dev_warn(icd->parent, | 1657 | dev_warn(pcdev_to_dev(pcdev), |
1160 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | 1658 | "Flags incompatible: camera 0x%x, host 0x%lx\n", |
1161 | cfg.flags, bus_flags); | 1659 | cfg.flags, bus_flags); |
1162 | return -EINVAL; | 1660 | return -EINVAL; |
@@ -1168,66 +1666,56 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, | |||
1168 | return ret; | 1666 | return ret; |
1169 | } | 1667 | } |
1170 | 1668 | ||
1171 | static const struct soc_mbus_pixelfmt pxa_camera_formats[] = { | 1669 | static const struct pxa_mbus_pixelfmt pxa_camera_formats[] = { |
1172 | { | 1670 | { |
1173 | .fourcc = V4L2_PIX_FMT_YUV422P, | 1671 | .fourcc = V4L2_PIX_FMT_YUV422P, |
1174 | .name = "Planar YUV422 16 bit", | 1672 | .name = "Planar YUV422 16 bit", |
1175 | .bits_per_sample = 8, | 1673 | .bits_per_sample = 8, |
1176 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 1674 | .packing = PXA_MBUS_PACKING_2X8_PADHI, |
1177 | .order = SOC_MBUS_ORDER_LE, | 1675 | .order = PXA_MBUS_ORDER_LE, |
1178 | .layout = SOC_MBUS_LAYOUT_PLANAR_2Y_U_V, | 1676 | .layout = PXA_MBUS_LAYOUT_PLANAR_2Y_U_V, |
1179 | }, | 1677 | }, |
1180 | }; | 1678 | }; |
1181 | 1679 | ||
1182 | /* This will be corrected as we get more formats */ | 1680 | /* This will be corrected as we get more formats */ |
1183 | static bool pxa_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) | 1681 | static bool pxa_camera_packing_supported(const struct pxa_mbus_pixelfmt *fmt) |
1184 | { | 1682 | { |
1185 | return fmt->packing == SOC_MBUS_PACKING_NONE || | 1683 | return fmt->packing == PXA_MBUS_PACKING_NONE || |
1186 | (fmt->bits_per_sample == 8 && | 1684 | (fmt->bits_per_sample == 8 && |
1187 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || | 1685 | fmt->packing == PXA_MBUS_PACKING_2X8_PADHI) || |
1188 | (fmt->bits_per_sample > 8 && | 1686 | (fmt->bits_per_sample > 8 && |
1189 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | 1687 | fmt->packing == PXA_MBUS_PACKING_EXTEND16); |
1190 | } | 1688 | } |
1191 | 1689 | ||
1192 | static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, | 1690 | static int pxa_camera_get_formats(struct v4l2_device *v4l2_dev, |
1691 | unsigned int idx, | ||
1193 | struct soc_camera_format_xlate *xlate) | 1692 | struct soc_camera_format_xlate *xlate) |
1194 | { | 1693 | { |
1195 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1694 | struct pxa_camera_dev *pcdev = v4l2_dev_to_pcdev(v4l2_dev); |
1196 | struct device *dev = icd->parent; | ||
1197 | int formats = 0, ret; | 1695 | int formats = 0, ret; |
1198 | struct pxa_cam *cam; | ||
1199 | struct v4l2_subdev_mbus_code_enum code = { | 1696 | struct v4l2_subdev_mbus_code_enum code = { |
1200 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | 1697 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
1201 | .index = idx, | 1698 | .index = idx, |
1202 | }; | 1699 | }; |
1203 | const struct soc_mbus_pixelfmt *fmt; | 1700 | const struct pxa_mbus_pixelfmt *fmt; |
1204 | 1701 | ||
1205 | ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); | 1702 | ret = sensor_call(pcdev, pad, enum_mbus_code, NULL, &code); |
1206 | if (ret < 0) | 1703 | if (ret < 0) |
1207 | /* No more formats */ | 1704 | /* No more formats */ |
1208 | return 0; | 1705 | return 0; |
1209 | 1706 | ||
1210 | fmt = soc_mbus_get_fmtdesc(code.code); | 1707 | fmt = pxa_mbus_get_fmtdesc(code.code); |
1211 | if (!fmt) { | 1708 | if (!fmt) { |
1212 | dev_err(dev, "Invalid format code #%u: %d\n", idx, code.code); | 1709 | dev_err(pcdev_to_dev(pcdev), |
1710 | "Invalid format code #%u: %d\n", idx, code.code); | ||
1213 | return 0; | 1711 | return 0; |
1214 | } | 1712 | } |
1215 | 1713 | ||
1216 | /* This also checks support for the requested bits-per-sample */ | 1714 | /* This also checks support for the requested bits-per-sample */ |
1217 | ret = pxa_camera_try_bus_param(icd, fmt->bits_per_sample); | 1715 | ret = pxa_camera_try_bus_param(pcdev, fmt->bits_per_sample); |
1218 | if (ret < 0) | 1716 | if (ret < 0) |
1219 | return 0; | 1717 | return 0; |
1220 | 1718 | ||
1221 | if (!icd->host_priv) { | ||
1222 | cam = kzalloc(sizeof(*cam), GFP_KERNEL); | ||
1223 | if (!cam) | ||
1224 | return -ENOMEM; | ||
1225 | |||
1226 | icd->host_priv = cam; | ||
1227 | } else { | ||
1228 | cam = icd->host_priv; | ||
1229 | } | ||
1230 | |||
1231 | switch (code.code) { | 1719 | switch (code.code) { |
1232 | case MEDIA_BUS_FMT_UYVY8_2X8: | 1720 | case MEDIA_BUS_FMT_UYVY8_2X8: |
1233 | formats++; | 1721 | formats++; |
@@ -1235,25 +1723,29 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id | |||
1235 | xlate->host_fmt = &pxa_camera_formats[0]; | 1723 | xlate->host_fmt = &pxa_camera_formats[0]; |
1236 | xlate->code = code.code; | 1724 | xlate->code = code.code; |
1237 | xlate++; | 1725 | xlate++; |
1238 | dev_dbg(dev, "Providing format %s using code %d\n", | 1726 | dev_dbg(pcdev_to_dev(pcdev), |
1727 | "Providing format %s using code %d\n", | ||
1239 | pxa_camera_formats[0].name, code.code); | 1728 | pxa_camera_formats[0].name, code.code); |
1240 | } | 1729 | } |
1730 | /* fall through */ | ||
1241 | case MEDIA_BUS_FMT_VYUY8_2X8: | 1731 | case MEDIA_BUS_FMT_VYUY8_2X8: |
1242 | case MEDIA_BUS_FMT_YUYV8_2X8: | 1732 | case MEDIA_BUS_FMT_YUYV8_2X8: |
1243 | case MEDIA_BUS_FMT_YVYU8_2X8: | 1733 | case MEDIA_BUS_FMT_YVYU8_2X8: |
1244 | case MEDIA_BUS_FMT_RGB565_2X8_LE: | 1734 | case MEDIA_BUS_FMT_RGB565_2X8_LE: |
1245 | case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: | 1735 | case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: |
1246 | if (xlate) | 1736 | if (xlate) |
1247 | dev_dbg(dev, "Providing format %s packed\n", | 1737 | dev_dbg(pcdev_to_dev(pcdev), |
1738 | "Providing format %s packed\n", | ||
1248 | fmt->name); | 1739 | fmt->name); |
1249 | break; | 1740 | break; |
1250 | default: | 1741 | default: |
1251 | if (!pxa_camera_packing_supported(fmt)) | 1742 | if (!pxa_camera_packing_supported(fmt)) |
1252 | return 0; | 1743 | return 0; |
1253 | if (xlate) | 1744 | if (xlate) |
1254 | dev_dbg(dev, | 1745 | dev_dbg(pcdev_to_dev(pcdev), |
1255 | "Providing format %s in pass-through mode\n", | 1746 | "Providing format %s in pass-through mode\n", |
1256 | fmt->name); | 1747 | fmt->name); |
1748 | break; | ||
1257 | } | 1749 | } |
1258 | 1750 | ||
1259 | /* Generic pass-through */ | 1751 | /* Generic pass-through */ |
@@ -1267,10 +1759,22 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id | |||
1267 | return formats; | 1759 | return formats; |
1268 | } | 1760 | } |
1269 | 1761 | ||
1270 | static void pxa_camera_put_formats(struct soc_camera_device *icd) | 1762 | static int pxa_camera_build_formats(struct pxa_camera_dev *pcdev) |
1271 | { | 1763 | { |
1272 | kfree(icd->host_priv); | 1764 | struct soc_camera_format_xlate *xlate; |
1273 | icd->host_priv = NULL; | 1765 | |
1766 | xlate = pxa_mbus_build_fmts_xlate(&pcdev->v4l2_dev, pcdev->sensor, | ||
1767 | pxa_camera_get_formats); | ||
1768 | if (IS_ERR(xlate)) | ||
1769 | return PTR_ERR(xlate); | ||
1770 | |||
1771 | pcdev->user_formats = xlate; | ||
1772 | return 0; | ||
1773 | } | ||
1774 | |||
1775 | static void pxa_camera_destroy_formats(struct pxa_camera_dev *pcdev) | ||
1776 | { | ||
1777 | kfree(pcdev->user_formats); | ||
1274 | } | 1778 | } |
1275 | 1779 | ||
1276 | static int pxa_camera_check_frame(u32 width, u32 height) | 1780 | static int pxa_camera_check_frame(u32 width, u32 height) |
@@ -1280,158 +1784,72 @@ static int pxa_camera_check_frame(u32 width, u32 height) | |||
1280 | (width & 0x01); | 1784 | (width & 0x01); |
1281 | } | 1785 | } |
1282 | 1786 | ||
1283 | static int pxa_camera_set_crop(struct soc_camera_device *icd, | 1787 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1284 | const struct v4l2_crop *a) | 1788 | static int pxac_vidioc_g_register(struct file *file, void *priv, |
1789 | struct v4l2_dbg_register *reg) | ||
1285 | { | 1790 | { |
1286 | const struct v4l2_rect *rect = &a->c; | 1791 | struct pxa_camera_dev *pcdev = video_drvdata(file); |
1287 | struct device *dev = icd->parent; | ||
1288 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1289 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1290 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1291 | struct soc_camera_sense sense = { | ||
1292 | .master_clock = pcdev->mclk, | ||
1293 | .pixel_clock_max = pcdev->ciclk / 4, | ||
1294 | }; | ||
1295 | struct v4l2_subdev_format fmt = { | ||
1296 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1297 | }; | ||
1298 | struct v4l2_mbus_framefmt *mf = &fmt.format; | ||
1299 | struct pxa_cam *cam = icd->host_priv; | ||
1300 | u32 fourcc = icd->current_fmt->host_fmt->fourcc; | ||
1301 | int ret; | ||
1302 | |||
1303 | /* If PCLK is used to latch data from the sensor, check sense */ | ||
1304 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) | ||
1305 | icd->sense = &sense; | ||
1306 | |||
1307 | ret = v4l2_subdev_call(sd, video, s_crop, a); | ||
1308 | |||
1309 | icd->sense = NULL; | ||
1310 | |||
1311 | if (ret < 0) { | ||
1312 | dev_warn(dev, "Failed to crop to %ux%u@%u:%u\n", | ||
1313 | rect->width, rect->height, rect->left, rect->top); | ||
1314 | return ret; | ||
1315 | } | ||
1316 | 1792 | ||
1317 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | 1793 | if (reg->reg > CIBR2) |
1318 | if (ret < 0) | 1794 | return -ERANGE; |
1319 | return ret; | ||
1320 | |||
1321 | if (pxa_camera_check_frame(mf->width, mf->height)) { | ||
1322 | /* | ||
1323 | * Camera cropping produced a frame beyond our capabilities. | ||
1324 | * FIXME: just extract a subframe, that we can process. | ||
1325 | */ | ||
1326 | v4l_bound_align_image(&mf->width, 48, 2048, 1, | ||
1327 | &mf->height, 32, 2048, 0, | ||
1328 | fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); | ||
1329 | ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &fmt); | ||
1330 | if (ret < 0) | ||
1331 | return ret; | ||
1332 | 1795 | ||
1333 | if (pxa_camera_check_frame(mf->width, mf->height)) { | 1796 | reg->val = __raw_readl(pcdev->base + reg->reg); |
1334 | dev_warn(icd->parent, | 1797 | reg->size = sizeof(__u32); |
1335 | "Inconsistent state. Use S_FMT to repair\n"); | 1798 | return 0; |
1336 | return -EINVAL; | ||
1337 | } | ||
1338 | } | ||
1339 | |||
1340 | if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { | ||
1341 | if (sense.pixel_clock > sense.pixel_clock_max) { | ||
1342 | dev_err(dev, | ||
1343 | "pixel clock %lu set by the camera too high!", | ||
1344 | sense.pixel_clock); | ||
1345 | return -EIO; | ||
1346 | } | ||
1347 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); | ||
1348 | } | ||
1349 | |||
1350 | icd->user_width = mf->width; | ||
1351 | icd->user_height = mf->height; | ||
1352 | |||
1353 | pxa_camera_setup_cicr(icd, cam->flags, fourcc); | ||
1354 | |||
1355 | return ret; | ||
1356 | } | 1799 | } |
1357 | 1800 | ||
1358 | static int pxa_camera_set_fmt(struct soc_camera_device *icd, | 1801 | static int pxac_vidioc_s_register(struct file *file, void *priv, |
1359 | struct v4l2_format *f) | 1802 | const struct v4l2_dbg_register *reg) |
1360 | { | 1803 | { |
1361 | struct device *dev = icd->parent; | 1804 | struct pxa_camera_dev *pcdev = video_drvdata(file); |
1362 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1363 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1364 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1365 | const struct soc_camera_format_xlate *xlate = NULL; | ||
1366 | struct soc_camera_sense sense = { | ||
1367 | .master_clock = pcdev->mclk, | ||
1368 | .pixel_clock_max = pcdev->ciclk / 4, | ||
1369 | }; | ||
1370 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1371 | struct v4l2_subdev_format format = { | ||
1372 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1373 | }; | ||
1374 | struct v4l2_mbus_framefmt *mf = &format.format; | ||
1375 | int ret; | ||
1376 | 1805 | ||
1377 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | 1806 | if (reg->reg > CIBR2) |
1378 | if (!xlate) { | 1807 | return -ERANGE; |
1379 | dev_warn(dev, "Format %x not found\n", pix->pixelformat); | 1808 | if (reg->size != sizeof(__u32)) |
1380 | return -EINVAL; | 1809 | return -EINVAL; |
1381 | } | 1810 | __raw_writel(reg->val, pcdev->base + reg->reg); |
1382 | 1811 | return 0; | |
1383 | /* If PCLK is used to latch data from the sensor, check sense */ | 1812 | } |
1384 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) | 1813 | #endif |
1385 | /* The caller holds a mutex. */ | ||
1386 | icd->sense = &sense; | ||
1387 | |||
1388 | mf->width = pix->width; | ||
1389 | mf->height = pix->height; | ||
1390 | mf->field = pix->field; | ||
1391 | mf->colorspace = pix->colorspace; | ||
1392 | mf->code = xlate->code; | ||
1393 | 1814 | ||
1394 | ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); | 1815 | static int pxac_vidioc_enum_fmt_vid_cap(struct file *filp, void *priv, |
1816 | struct v4l2_fmtdesc *f) | ||
1817 | { | ||
1818 | struct pxa_camera_dev *pcdev = video_drvdata(filp); | ||
1819 | const struct pxa_mbus_pixelfmt *format; | ||
1820 | unsigned int idx; | ||
1395 | 1821 | ||
1396 | if (mf->code != xlate->code) | 1822 | for (idx = 0; pcdev->user_formats[idx].code; idx++); |
1823 | if (f->index >= idx) | ||
1397 | return -EINVAL; | 1824 | return -EINVAL; |
1398 | 1825 | ||
1399 | icd->sense = NULL; | 1826 | format = pcdev->user_formats[f->index].host_fmt; |
1400 | 1827 | f->pixelformat = format->fourcc; | |
1401 | if (ret < 0) { | 1828 | return 0; |
1402 | dev_warn(dev, "Failed to configure for format %x\n", | 1829 | } |
1403 | pix->pixelformat); | ||
1404 | } else if (pxa_camera_check_frame(mf->width, mf->height)) { | ||
1405 | dev_warn(dev, | ||
1406 | "Camera driver produced an unsupported frame %dx%d\n", | ||
1407 | mf->width, mf->height); | ||
1408 | ret = -EINVAL; | ||
1409 | } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { | ||
1410 | if (sense.pixel_clock > sense.pixel_clock_max) { | ||
1411 | dev_err(dev, | ||
1412 | "pixel clock %lu set by the camera too high!", | ||
1413 | sense.pixel_clock); | ||
1414 | return -EIO; | ||
1415 | } | ||
1416 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); | ||
1417 | } | ||
1418 | |||
1419 | if (ret < 0) | ||
1420 | return ret; | ||
1421 | 1830 | ||
1422 | pix->width = mf->width; | 1831 | static int pxac_vidioc_g_fmt_vid_cap(struct file *filp, void *priv, |
1423 | pix->height = mf->height; | 1832 | struct v4l2_format *f) |
1424 | pix->field = mf->field; | 1833 | { |
1425 | pix->colorspace = mf->colorspace; | 1834 | struct pxa_camera_dev *pcdev = video_drvdata(filp); |
1426 | icd->current_fmt = xlate; | 1835 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1427 | 1836 | ||
1428 | return ret; | 1837 | pix->width = pcdev->current_pix.width; |
1838 | pix->height = pcdev->current_pix.height; | ||
1839 | pix->bytesperline = pcdev->current_pix.bytesperline; | ||
1840 | pix->sizeimage = pcdev->current_pix.sizeimage; | ||
1841 | pix->field = pcdev->current_pix.field; | ||
1842 | pix->pixelformat = pcdev->current_fmt->host_fmt->fourcc; | ||
1843 | pix->colorspace = pcdev->current_pix.colorspace; | ||
1844 | dev_dbg(pcdev_to_dev(pcdev), "current_fmt->fourcc: 0x%08x\n", | ||
1845 | pcdev->current_fmt->host_fmt->fourcc); | ||
1846 | return 0; | ||
1429 | } | 1847 | } |
1430 | 1848 | ||
1431 | static int pxa_camera_try_fmt(struct soc_camera_device *icd, | 1849 | static int pxac_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, |
1432 | struct v4l2_format *f) | 1850 | struct v4l2_format *f) |
1433 | { | 1851 | { |
1434 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1852 | struct pxa_camera_dev *pcdev = video_drvdata(filp); |
1435 | const struct soc_camera_format_xlate *xlate; | 1853 | const struct soc_camera_format_xlate *xlate; |
1436 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1854 | struct v4l2_pix_format *pix = &f->fmt.pix; |
1437 | struct v4l2_subdev_pad_config pad_cfg; | 1855 | struct v4l2_subdev_pad_config pad_cfg; |
@@ -1442,9 +1860,9 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, | |||
1442 | __u32 pixfmt = pix->pixelformat; | 1860 | __u32 pixfmt = pix->pixelformat; |
1443 | int ret; | 1861 | int ret; |
1444 | 1862 | ||
1445 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 1863 | xlate = pxa_mbus_xlate_by_fourcc(pcdev->user_formats, pixfmt); |
1446 | if (!xlate) { | 1864 | if (!xlate) { |
1447 | dev_warn(icd->parent, "Format %x not found\n", pixfmt); | 1865 | dev_warn(pcdev_to_dev(pcdev), "Format %x not found\n", pixfmt); |
1448 | return -EINVAL; | 1866 | return -EINVAL; |
1449 | } | 1867 | } |
1450 | 1868 | ||
@@ -1458,90 +1876,311 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, | |||
1458 | &pix->height, 32, 2048, 0, | 1876 | &pix->height, 32, 2048, 0, |
1459 | pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); | 1877 | pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); |
1460 | 1878 | ||
1461 | /* limit to sensor capabilities */ | 1879 | v4l2_fill_mbus_format(mf, pix, xlate->code); |
1462 | mf->width = pix->width; | 1880 | ret = sensor_call(pcdev, pad, set_fmt, &pad_cfg, &format); |
1463 | mf->height = pix->height; | ||
1464 | /* Only progressive video supported so far */ | ||
1465 | mf->field = V4L2_FIELD_NONE; | ||
1466 | mf->colorspace = pix->colorspace; | ||
1467 | mf->code = xlate->code; | ||
1468 | |||
1469 | ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); | ||
1470 | if (ret < 0) | 1881 | if (ret < 0) |
1471 | return ret; | 1882 | return ret; |
1472 | 1883 | ||
1473 | pix->width = mf->width; | 1884 | v4l2_fill_pix_format(pix, mf); |
1474 | pix->height = mf->height; | ||
1475 | pix->colorspace = mf->colorspace; | ||
1476 | 1885 | ||
1886 | /* Only progressive video supported so far */ | ||
1477 | switch (mf->field) { | 1887 | switch (mf->field) { |
1478 | case V4L2_FIELD_ANY: | 1888 | case V4L2_FIELD_ANY: |
1479 | case V4L2_FIELD_NONE: | 1889 | case V4L2_FIELD_NONE: |
1480 | pix->field = V4L2_FIELD_NONE; | 1890 | pix->field = V4L2_FIELD_NONE; |
1481 | break; | 1891 | break; |
1482 | default: | 1892 | default: |
1483 | /* TODO: support interlaced at least in pass-through mode */ | 1893 | /* TODO: support interlaced at least in pass-through mode */ |
1484 | dev_err(icd->parent, "Field type %d unsupported.\n", | 1894 | dev_err(pcdev_to_dev(pcdev), "Field type %d unsupported.\n", |
1485 | mf->field); | 1895 | mf->field); |
1486 | return -EINVAL; | 1896 | return -EINVAL; |
1487 | } | 1897 | } |
1488 | 1898 | ||
1489 | return ret; | 1899 | ret = pxa_mbus_bytes_per_line(pix->width, xlate->host_fmt); |
1900 | if (ret < 0) | ||
1901 | return ret; | ||
1902 | |||
1903 | pix->bytesperline = ret; | ||
1904 | ret = pxa_mbus_image_size(xlate->host_fmt, pix->bytesperline, | ||
1905 | pix->height); | ||
1906 | if (ret < 0) | ||
1907 | return ret; | ||
1908 | |||
1909 | pix->sizeimage = ret; | ||
1910 | return 0; | ||
1490 | } | 1911 | } |
1491 | 1912 | ||
1492 | static int pxa_camera_reqbufs(struct soc_camera_device *icd, | 1913 | static int pxac_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, |
1493 | struct v4l2_requestbuffers *p) | 1914 | struct v4l2_format *f) |
1494 | { | 1915 | { |
1495 | int i; | 1916 | struct pxa_camera_dev *pcdev = video_drvdata(filp); |
1917 | const struct soc_camera_format_xlate *xlate; | ||
1918 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1919 | struct v4l2_subdev_format format = { | ||
1920 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1921 | }; | ||
1922 | unsigned long flags; | ||
1923 | int ret, is_busy; | ||
1496 | 1924 | ||
1497 | /* | 1925 | dev_dbg(pcdev_to_dev(pcdev), |
1498 | * This is for locking debugging only. I removed spinlocks and now I | 1926 | "s_fmt_vid_cap(pix=%dx%d:%x)\n", |
1499 | * check whether .prepare is ever called on a linked buffer, or whether | 1927 | pix->width, pix->height, pix->pixelformat); |
1500 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now | 1928 | |
1501 | * it hadn't triggered | 1929 | spin_lock_irqsave(&pcdev->lock, flags); |
1502 | */ | 1930 | is_busy = pcdev->active || vb2_is_busy(&pcdev->vb2_vq); |
1503 | for (i = 0; i < p->count; i++) { | 1931 | spin_unlock_irqrestore(&pcdev->lock, flags); |
1504 | struct pxa_buffer *buf = container_of(icd->vb_vidq.bufs[i], | 1932 | |
1505 | struct pxa_buffer, vb); | 1933 | if (is_busy) |
1506 | buf->inwork = 0; | 1934 | return -EBUSY; |
1507 | INIT_LIST_HEAD(&buf->vb.queue); | 1935 | |
1936 | ret = pxac_vidioc_try_fmt_vid_cap(filp, priv, f); | ||
1937 | if (ret) | ||
1938 | return ret; | ||
1939 | |||
1940 | xlate = pxa_mbus_xlate_by_fourcc(pcdev->user_formats, | ||
1941 | pix->pixelformat); | ||
1942 | v4l2_fill_mbus_format(&format.format, pix, xlate->code); | ||
1943 | ret = sensor_call(pcdev, pad, set_fmt, NULL, &format); | ||
1944 | if (ret < 0) { | ||
1945 | dev_warn(pcdev_to_dev(pcdev), | ||
1946 | "Failed to configure for format %x\n", | ||
1947 | pix->pixelformat); | ||
1948 | } else if (pxa_camera_check_frame(pix->width, pix->height)) { | ||
1949 | dev_warn(pcdev_to_dev(pcdev), | ||
1950 | "Camera driver produced an unsupported frame %dx%d\n", | ||
1951 | pix->width, pix->height); | ||
1952 | return -EINVAL; | ||
1508 | } | 1953 | } |
1509 | 1954 | ||
1955 | pcdev->current_fmt = xlate; | ||
1956 | pcdev->current_pix = *pix; | ||
1957 | |||
1958 | ret = pxa_camera_set_bus_param(pcdev); | ||
1959 | return ret; | ||
1960 | } | ||
1961 | |||
1962 | static int pxac_vidioc_querycap(struct file *file, void *priv, | ||
1963 | struct v4l2_capability *cap) | ||
1964 | { | ||
1965 | strlcpy(cap->bus_info, "platform:pxa-camera", sizeof(cap->bus_info)); | ||
1966 | strlcpy(cap->driver, PXA_CAM_DRV_NAME, sizeof(cap->driver)); | ||
1967 | strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card)); | ||
1968 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
1969 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
1970 | |||
1510 | return 0; | 1971 | return 0; |
1511 | } | 1972 | } |
1512 | 1973 | ||
1513 | static unsigned int pxa_camera_poll(struct file *file, poll_table *pt) | 1974 | static int pxac_vidioc_enum_input(struct file *file, void *priv, |
1975 | struct v4l2_input *i) | ||
1514 | { | 1976 | { |
1515 | struct soc_camera_device *icd = file->private_data; | 1977 | if (i->index > 0) |
1516 | struct pxa_buffer *buf; | 1978 | return -EINVAL; |
1517 | 1979 | ||
1518 | buf = list_entry(icd->vb_vidq.stream.next, struct pxa_buffer, | 1980 | i->type = V4L2_INPUT_TYPE_CAMERA; |
1519 | vb.stream); | 1981 | strlcpy(i->name, "Camera", sizeof(i->name)); |
1520 | 1982 | ||
1521 | poll_wait(file, &buf->vb.done, pt); | 1983 | return 0; |
1984 | } | ||
1522 | 1985 | ||
1523 | if (buf->vb.state == VIDEOBUF_DONE || | 1986 | static int pxac_vidioc_g_input(struct file *file, void *priv, unsigned int *i) |
1524 | buf->vb.state == VIDEOBUF_ERROR) | 1987 | { |
1525 | return POLLIN|POLLRDNORM; | 1988 | *i = 0; |
1526 | 1989 | ||
1527 | return 0; | 1990 | return 0; |
1528 | } | 1991 | } |
1529 | 1992 | ||
1530 | static int pxa_camera_querycap(struct soc_camera_host *ici, | 1993 | static int pxac_vidioc_s_input(struct file *file, void *priv, unsigned int i) |
1531 | struct v4l2_capability *cap) | ||
1532 | { | 1994 | { |
1533 | /* cap->name is set by the firendly caller:-> */ | 1995 | if (i > 0) |
1534 | strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card)); | 1996 | return -EINVAL; |
1535 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
1536 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
1537 | 1997 | ||
1538 | return 0; | 1998 | return 0; |
1539 | } | 1999 | } |
1540 | 2000 | ||
2001 | static int pxac_fops_camera_open(struct file *filp) | ||
2002 | { | ||
2003 | struct pxa_camera_dev *pcdev = video_drvdata(filp); | ||
2004 | int ret; | ||
2005 | |||
2006 | mutex_lock(&pcdev->mlock); | ||
2007 | ret = v4l2_fh_open(filp); | ||
2008 | if (ret < 0) | ||
2009 | goto out; | ||
2010 | |||
2011 | ret = sensor_call(pcdev, core, s_power, 1); | ||
2012 | if (ret) | ||
2013 | v4l2_fh_release(filp); | ||
2014 | out: | ||
2015 | mutex_unlock(&pcdev->mlock); | ||
2016 | return ret; | ||
2017 | } | ||
2018 | |||
2019 | static int pxac_fops_camera_release(struct file *filp) | ||
2020 | { | ||
2021 | struct pxa_camera_dev *pcdev = video_drvdata(filp); | ||
2022 | int ret; | ||
2023 | |||
2024 | ret = vb2_fop_release(filp); | ||
2025 | if (ret < 0) | ||
2026 | return ret; | ||
2027 | |||
2028 | mutex_lock(&pcdev->mlock); | ||
2029 | ret = sensor_call(pcdev, core, s_power, 0); | ||
2030 | mutex_unlock(&pcdev->mlock); | ||
2031 | |||
2032 | return ret; | ||
2033 | } | ||
2034 | |||
2035 | static const struct v4l2_file_operations pxa_camera_fops = { | ||
2036 | .owner = THIS_MODULE, | ||
2037 | .open = pxac_fops_camera_open, | ||
2038 | .release = pxac_fops_camera_release, | ||
2039 | .read = vb2_fop_read, | ||
2040 | .poll = vb2_fop_poll, | ||
2041 | .mmap = vb2_fop_mmap, | ||
2042 | .unlocked_ioctl = video_ioctl2, | ||
2043 | }; | ||
2044 | |||
2045 | static const struct v4l2_ioctl_ops pxa_camera_ioctl_ops = { | ||
2046 | .vidioc_querycap = pxac_vidioc_querycap, | ||
2047 | |||
2048 | .vidioc_enum_input = pxac_vidioc_enum_input, | ||
2049 | .vidioc_g_input = pxac_vidioc_g_input, | ||
2050 | .vidioc_s_input = pxac_vidioc_s_input, | ||
2051 | |||
2052 | .vidioc_enum_fmt_vid_cap = pxac_vidioc_enum_fmt_vid_cap, | ||
2053 | .vidioc_g_fmt_vid_cap = pxac_vidioc_g_fmt_vid_cap, | ||
2054 | .vidioc_s_fmt_vid_cap = pxac_vidioc_s_fmt_vid_cap, | ||
2055 | .vidioc_try_fmt_vid_cap = pxac_vidioc_try_fmt_vid_cap, | ||
2056 | |||
2057 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
2058 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
2059 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
2060 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
2061 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
2062 | .vidioc_expbuf = vb2_ioctl_expbuf, | ||
2063 | .vidioc_streamon = vb2_ioctl_streamon, | ||
2064 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
2065 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
2066 | .vidioc_g_register = pxac_vidioc_g_register, | ||
2067 | .vidioc_s_register = pxac_vidioc_s_register, | ||
2068 | #endif | ||
2069 | }; | ||
2070 | |||
2071 | static struct v4l2_clk_ops pxa_camera_mclk_ops = { | ||
2072 | }; | ||
2073 | |||
2074 | static const struct video_device pxa_camera_videodev_template = { | ||
2075 | .name = "pxa-camera", | ||
2076 | .minor = -1, | ||
2077 | .fops = &pxa_camera_fops, | ||
2078 | .ioctl_ops = &pxa_camera_ioctl_ops, | ||
2079 | .release = video_device_release_empty, | ||
2080 | .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING, | ||
2081 | }; | ||
2082 | |||
2083 | static int pxa_camera_sensor_bound(struct v4l2_async_notifier *notifier, | ||
2084 | struct v4l2_subdev *subdev, | ||
2085 | struct v4l2_async_subdev *asd) | ||
2086 | { | ||
2087 | int err; | ||
2088 | struct v4l2_device *v4l2_dev = notifier->v4l2_dev; | ||
2089 | struct pxa_camera_dev *pcdev = v4l2_dev_to_pcdev(v4l2_dev); | ||
2090 | struct video_device *vdev = &pcdev->vdev; | ||
2091 | struct v4l2_pix_format *pix = &pcdev->current_pix; | ||
2092 | struct v4l2_subdev_format format = { | ||
2093 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
2094 | }; | ||
2095 | struct v4l2_mbus_framefmt *mf = &format.format; | ||
2096 | |||
2097 | dev_info(pcdev_to_dev(pcdev), "%s(): trying to bind a device\n", | ||
2098 | __func__); | ||
2099 | mutex_lock(&pcdev->mlock); | ||
2100 | *vdev = pxa_camera_videodev_template; | ||
2101 | vdev->v4l2_dev = v4l2_dev; | ||
2102 | vdev->lock = &pcdev->mlock; | ||
2103 | pcdev->sensor = subdev; | ||
2104 | pcdev->vdev.queue = &pcdev->vb2_vq; | ||
2105 | pcdev->vdev.v4l2_dev = &pcdev->v4l2_dev; | ||
2106 | pcdev->vdev.ctrl_handler = subdev->ctrl_handler; | ||
2107 | video_set_drvdata(&pcdev->vdev, pcdev); | ||
2108 | |||
2109 | err = pxa_camera_build_formats(pcdev); | ||
2110 | if (err) { | ||
2111 | dev_err(pcdev_to_dev(pcdev), "building formats failed: %d\n", | ||
2112 | err); | ||
2113 | goto out; | ||
2114 | } | ||
2115 | |||
2116 | pcdev->current_fmt = pcdev->user_formats; | ||
2117 | pix->field = V4L2_FIELD_NONE; | ||
2118 | pix->width = DEFAULT_WIDTH; | ||
2119 | pix->height = DEFAULT_HEIGHT; | ||
2120 | pix->bytesperline = | ||
2121 | pxa_mbus_bytes_per_line(pix->width, | ||
2122 | pcdev->current_fmt->host_fmt); | ||
2123 | pix->sizeimage = | ||
2124 | pxa_mbus_image_size(pcdev->current_fmt->host_fmt, | ||
2125 | pix->bytesperline, pix->height); | ||
2126 | pix->pixelformat = pcdev->current_fmt->host_fmt->fourcc; | ||
2127 | v4l2_fill_mbus_format(mf, pix, pcdev->current_fmt->code); | ||
2128 | err = sensor_call(pcdev, pad, set_fmt, NULL, &format); | ||
2129 | if (err) | ||
2130 | goto out; | ||
2131 | |||
2132 | v4l2_fill_pix_format(pix, mf); | ||
2133 | pr_info("%s(): colorspace=0x%x pixfmt=0x%x\n", | ||
2134 | __func__, pix->colorspace, pix->pixelformat); | ||
2135 | |||
2136 | err = pxa_camera_init_videobuf2(pcdev); | ||
2137 | if (err) | ||
2138 | goto out; | ||
2139 | |||
2140 | err = video_register_device(&pcdev->vdev, VFL_TYPE_GRABBER, -1); | ||
2141 | if (err) { | ||
2142 | v4l2_err(v4l2_dev, "register video device failed: %d\n", err); | ||
2143 | pcdev->sensor = NULL; | ||
2144 | } else { | ||
2145 | dev_info(pcdev_to_dev(pcdev), | ||
2146 | "PXA Camera driver attached to camera %s\n", | ||
2147 | subdev->name); | ||
2148 | } | ||
2149 | out: | ||
2150 | mutex_unlock(&pcdev->mlock); | ||
2151 | return err; | ||
2152 | } | ||
2153 | |||
2154 | static void pxa_camera_sensor_unbind(struct v4l2_async_notifier *notifier, | ||
2155 | struct v4l2_subdev *subdev, | ||
2156 | struct v4l2_async_subdev *asd) | ||
2157 | { | ||
2158 | struct pxa_camera_dev *pcdev = v4l2_dev_to_pcdev(notifier->v4l2_dev); | ||
2159 | |||
2160 | mutex_lock(&pcdev->mlock); | ||
2161 | dev_info(pcdev_to_dev(pcdev), | ||
2162 | "PXA Camera driver detached from camera %s\n", | ||
2163 | subdev->name); | ||
2164 | |||
2165 | /* disable capture, disable interrupts */ | ||
2166 | __raw_writel(0x3ff, pcdev->base + CICR0); | ||
2167 | |||
2168 | /* Stop DMA engine */ | ||
2169 | pxa_dma_stop_channels(pcdev); | ||
2170 | |||
2171 | pxa_camera_destroy_formats(pcdev); | ||
2172 | video_unregister_device(&pcdev->vdev); | ||
2173 | pcdev->sensor = NULL; | ||
2174 | |||
2175 | mutex_unlock(&pcdev->mlock); | ||
2176 | } | ||
2177 | |||
2178 | /* | ||
2179 | * Driver probe, remove, suspend and resume operations | ||
2180 | */ | ||
1541 | static int pxa_camera_suspend(struct device *dev) | 2181 | static int pxa_camera_suspend(struct device *dev) |
1542 | { | 2182 | { |
1543 | struct soc_camera_host *ici = to_soc_camera_host(dev); | 2183 | struct pxa_camera_dev *pcdev = dev_get_drvdata(dev); |
1544 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1545 | int i = 0, ret = 0; | 2184 | int i = 0, ret = 0; |
1546 | 2185 | ||
1547 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR0); | 2186 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR0); |
@@ -1550,9 +2189,8 @@ static int pxa_camera_suspend(struct device *dev) | |||
1550 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3); | 2189 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3); |
1551 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4); | 2190 | pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4); |
1552 | 2191 | ||
1553 | if (pcdev->soc_host.icd) { | 2192 | if (pcdev->sensor) { |
1554 | struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->soc_host.icd); | 2193 | ret = sensor_call(pcdev, core, s_power, 0); |
1555 | ret = v4l2_subdev_call(sd, core, s_power, 0); | ||
1556 | if (ret == -ENOIOCTLCMD) | 2194 | if (ret == -ENOIOCTLCMD) |
1557 | ret = 0; | 2195 | ret = 0; |
1558 | } | 2196 | } |
@@ -1562,8 +2200,7 @@ static int pxa_camera_suspend(struct device *dev) | |||
1562 | 2200 | ||
1563 | static int pxa_camera_resume(struct device *dev) | 2201 | static int pxa_camera_resume(struct device *dev) |
1564 | { | 2202 | { |
1565 | struct soc_camera_host *ici = to_soc_camera_host(dev); | 2203 | struct pxa_camera_dev *pcdev = dev_get_drvdata(dev); |
1566 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1567 | int i = 0, ret = 0; | 2204 | int i = 0, ret = 0; |
1568 | 2205 | ||
1569 | __raw_writel(pcdev->save_cicr[i++] & ~CICR0_ENB, pcdev->base + CICR0); | 2206 | __raw_writel(pcdev->save_cicr[i++] & ~CICR0_ENB, pcdev->base + CICR0); |
@@ -1572,9 +2209,8 @@ static int pxa_camera_resume(struct device *dev) | |||
1572 | __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3); | 2209 | __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3); |
1573 | __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4); | 2210 | __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4); |
1574 | 2211 | ||
1575 | if (pcdev->soc_host.icd) { | 2212 | if (pcdev->sensor) { |
1576 | struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->soc_host.icd); | 2213 | ret = sensor_call(pcdev, core, s_power, 1); |
1577 | ret = v4l2_subdev_call(sd, core, s_power, 1); | ||
1578 | if (ret == -ENOIOCTLCMD) | 2214 | if (ret == -ENOIOCTLCMD) |
1579 | ret = 0; | 2215 | ret = 0; |
1580 | } | 2216 | } |
@@ -1586,29 +2222,12 @@ static int pxa_camera_resume(struct device *dev) | |||
1586 | return ret; | 2222 | return ret; |
1587 | } | 2223 | } |
1588 | 2224 | ||
1589 | static struct soc_camera_host_ops pxa_soc_camera_host_ops = { | ||
1590 | .owner = THIS_MODULE, | ||
1591 | .add = pxa_camera_add_device, | ||
1592 | .remove = pxa_camera_remove_device, | ||
1593 | .clock_start = pxa_camera_clock_start, | ||
1594 | .clock_stop = pxa_camera_clock_stop, | ||
1595 | .set_crop = pxa_camera_set_crop, | ||
1596 | .get_formats = pxa_camera_get_formats, | ||
1597 | .put_formats = pxa_camera_put_formats, | ||
1598 | .set_fmt = pxa_camera_set_fmt, | ||
1599 | .try_fmt = pxa_camera_try_fmt, | ||
1600 | .init_videobuf = pxa_camera_init_videobuf, | ||
1601 | .reqbufs = pxa_camera_reqbufs, | ||
1602 | .poll = pxa_camera_poll, | ||
1603 | .querycap = pxa_camera_querycap, | ||
1604 | .set_bus_param = pxa_camera_set_bus_param, | ||
1605 | }; | ||
1606 | |||
1607 | static int pxa_camera_pdata_from_dt(struct device *dev, | 2225 | static int pxa_camera_pdata_from_dt(struct device *dev, |
1608 | struct pxa_camera_dev *pcdev) | 2226 | struct pxa_camera_dev *pcdev, |
2227 | struct v4l2_async_subdev *asd) | ||
1609 | { | 2228 | { |
1610 | u32 mclk_rate; | 2229 | u32 mclk_rate; |
1611 | struct device_node *np = dev->of_node; | 2230 | struct device_node *remote, *np = dev->of_node; |
1612 | struct v4l2_of_endpoint ep; | 2231 | struct v4l2_of_endpoint ep; |
1613 | int err = of_property_read_u32(np, "clock-frequency", | 2232 | int err = of_property_read_u32(np, "clock-frequency", |
1614 | &mclk_rate); | 2233 | &mclk_rate); |
@@ -1660,6 +2279,15 @@ static int pxa_camera_pdata_from_dt(struct device *dev, | |||
1660 | if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | 2279 | if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) |
1661 | pcdev->platform_flags |= PXA_CAMERA_PCLK_EN; | 2280 | pcdev->platform_flags |= PXA_CAMERA_PCLK_EN; |
1662 | 2281 | ||
2282 | asd->match_type = V4L2_ASYNC_MATCH_OF; | ||
2283 | remote = of_graph_get_remote_port(np); | ||
2284 | if (remote) { | ||
2285 | asd->match.of.node = remote; | ||
2286 | of_node_put(remote); | ||
2287 | } else { | ||
2288 | dev_notice(dev, "no remote for %s\n", of_node_full_name(np)); | ||
2289 | } | ||
2290 | |||
1663 | out: | 2291 | out: |
1664 | of_node_put(np); | 2292 | of_node_put(np); |
1665 | 2293 | ||
@@ -1678,6 +2306,7 @@ static int pxa_camera_probe(struct platform_device *pdev) | |||
1678 | }; | 2306 | }; |
1679 | dma_cap_mask_t mask; | 2307 | dma_cap_mask_t mask; |
1680 | struct pxad_param params; | 2308 | struct pxad_param params; |
2309 | char clk_name[V4L2_CLK_NAME_SIZE]; | ||
1681 | int irq; | 2310 | int irq; |
1682 | int err = 0, i; | 2311 | int err = 0, i; |
1683 | 2312 | ||
@@ -1700,10 +2329,14 @@ static int pxa_camera_probe(struct platform_device *pdev) | |||
1700 | 2329 | ||
1701 | pcdev->pdata = pdev->dev.platform_data; | 2330 | pcdev->pdata = pdev->dev.platform_data; |
1702 | if (&pdev->dev.of_node && !pcdev->pdata) { | 2331 | if (&pdev->dev.of_node && !pcdev->pdata) { |
1703 | err = pxa_camera_pdata_from_dt(&pdev->dev, pcdev); | 2332 | err = pxa_camera_pdata_from_dt(&pdev->dev, pcdev, &pcdev->asd); |
1704 | } else { | 2333 | } else { |
1705 | pcdev->platform_flags = pcdev->pdata->flags; | 2334 | pcdev->platform_flags = pcdev->pdata->flags; |
1706 | pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; | 2335 | pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; |
2336 | pcdev->asd.match_type = V4L2_ASYNC_MATCH_I2C; | ||
2337 | pcdev->asd.match.i2c.adapter_id = | ||
2338 | pcdev->pdata->sensor_i2c_adapter_id; | ||
2339 | pcdev->asd.match.i2c.address = pcdev->pdata->sensor_i2c_address; | ||
1707 | } | 2340 | } |
1708 | if (err < 0) | 2341 | if (err < 0) |
1709 | return err; | 2342 | return err; |
@@ -1735,6 +2368,7 @@ static int pxa_camera_probe(struct platform_device *pdev) | |||
1735 | 2368 | ||
1736 | INIT_LIST_HEAD(&pcdev->capture); | 2369 | INIT_LIST_HEAD(&pcdev->capture); |
1737 | spin_lock_init(&pcdev->lock); | 2370 | spin_lock_init(&pcdev->lock); |
2371 | mutex_init(&pcdev->mlock); | ||
1738 | 2372 | ||
1739 | /* | 2373 | /* |
1740 | * Request the regions. | 2374 | * Request the regions. |
@@ -1767,6 +2401,7 @@ static int pxa_camera_probe(struct platform_device *pdev) | |||
1767 | ¶ms, &pdev->dev, "CI_U"); | 2401 | ¶ms, &pdev->dev, "CI_U"); |
1768 | if (!pcdev->dma_chans[1]) { | 2402 | if (!pcdev->dma_chans[1]) { |
1769 | dev_err(&pdev->dev, "Can't request DMA for Y\n"); | 2403 | dev_err(&pdev->dev, "Can't request DMA for Y\n"); |
2404 | err = -ENODEV; | ||
1770 | goto exit_free_dma_y; | 2405 | goto exit_free_dma_y; |
1771 | } | 2406 | } |
1772 | 2407 | ||
@@ -1776,6 +2411,7 @@ static int pxa_camera_probe(struct platform_device *pdev) | |||
1776 | ¶ms, &pdev->dev, "CI_V"); | 2411 | ¶ms, &pdev->dev, "CI_V"); |
1777 | if (!pcdev->dma_chans[2]) { | 2412 | if (!pcdev->dma_chans[2]) { |
1778 | dev_err(&pdev->dev, "Can't request DMA for V\n"); | 2413 | dev_err(&pdev->dev, "Can't request DMA for V\n"); |
2414 | err = -ENODEV; | ||
1779 | goto exit_free_dma_u; | 2415 | goto exit_free_dma_u; |
1780 | } | 2416 | } |
1781 | 2417 | ||
@@ -1797,19 +2433,50 @@ static int pxa_camera_probe(struct platform_device *pdev) | |||
1797 | goto exit_free_dma; | 2433 | goto exit_free_dma; |
1798 | } | 2434 | } |
1799 | 2435 | ||
1800 | pcdev->soc_host.drv_name = PXA_CAM_DRV_NAME; | ||
1801 | pcdev->soc_host.ops = &pxa_soc_camera_host_ops; | ||
1802 | pcdev->soc_host.priv = pcdev; | ||
1803 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; | ||
1804 | pcdev->soc_host.nr = pdev->id; | ||
1805 | tasklet_init(&pcdev->task_eof, pxa_camera_eof, (unsigned long)pcdev); | 2436 | tasklet_init(&pcdev->task_eof, pxa_camera_eof, (unsigned long)pcdev); |
1806 | 2437 | ||
1807 | err = soc_camera_host_register(&pcdev->soc_host); | 2438 | pxa_camera_activate(pcdev); |
2439 | |||
2440 | dev_set_drvdata(&pdev->dev, pcdev); | ||
2441 | err = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev); | ||
1808 | if (err) | 2442 | if (err) |
1809 | goto exit_free_dma; | 2443 | goto exit_free_dma; |
1810 | 2444 | ||
1811 | return 0; | 2445 | pcdev->asds[0] = &pcdev->asd; |
2446 | pcdev->notifier.subdevs = pcdev->asds; | ||
2447 | pcdev->notifier.num_subdevs = 1; | ||
2448 | pcdev->notifier.bound = pxa_camera_sensor_bound; | ||
2449 | pcdev->notifier.unbind = pxa_camera_sensor_unbind; | ||
1812 | 2450 | ||
2451 | if (!of_have_populated_dt()) | ||
2452 | pcdev->asd.match_type = V4L2_ASYNC_MATCH_I2C; | ||
2453 | |||
2454 | err = pxa_camera_init_videobuf2(pcdev); | ||
2455 | if (err) | ||
2456 | goto exit_free_v4l2dev; | ||
2457 | |||
2458 | if (pcdev->mclk) { | ||
2459 | v4l2_clk_name_i2c(clk_name, sizeof(clk_name), | ||
2460 | pcdev->asd.match.i2c.adapter_id, | ||
2461 | pcdev->asd.match.i2c.address); | ||
2462 | |||
2463 | pcdev->mclk_clk = v4l2_clk_register(&pxa_camera_mclk_ops, | ||
2464 | clk_name, NULL); | ||
2465 | if (IS_ERR(pcdev->mclk_clk)) { | ||
2466 | err = PTR_ERR(pcdev->mclk_clk); | ||
2467 | goto exit_free_v4l2dev; | ||
2468 | } | ||
2469 | } | ||
2470 | |||
2471 | err = v4l2_async_notifier_register(&pcdev->v4l2_dev, &pcdev->notifier); | ||
2472 | if (err) | ||
2473 | goto exit_free_clk; | ||
2474 | |||
2475 | return 0; | ||
2476 | exit_free_clk: | ||
2477 | v4l2_clk_unregister(pcdev->mclk_clk); | ||
2478 | exit_free_v4l2dev: | ||
2479 | v4l2_device_unregister(&pcdev->v4l2_dev); | ||
1813 | exit_free_dma: | 2480 | exit_free_dma: |
1814 | dma_release_channel(pcdev->dma_chans[2]); | 2481 | dma_release_channel(pcdev->dma_chans[2]); |
1815 | exit_free_dma_u: | 2482 | exit_free_dma_u: |
@@ -1821,15 +2488,15 @@ exit_free_dma_y: | |||
1821 | 2488 | ||
1822 | static int pxa_camera_remove(struct platform_device *pdev) | 2489 | static int pxa_camera_remove(struct platform_device *pdev) |
1823 | { | 2490 | { |
1824 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | 2491 | struct pxa_camera_dev *pcdev = dev_get_drvdata(&pdev->dev); |
1825 | struct pxa_camera_dev *pcdev = container_of(soc_host, | ||
1826 | struct pxa_camera_dev, soc_host); | ||
1827 | 2492 | ||
2493 | pxa_camera_deactivate(pcdev); | ||
1828 | dma_release_channel(pcdev->dma_chans[0]); | 2494 | dma_release_channel(pcdev->dma_chans[0]); |
1829 | dma_release_channel(pcdev->dma_chans[1]); | 2495 | dma_release_channel(pcdev->dma_chans[1]); |
1830 | dma_release_channel(pcdev->dma_chans[2]); | 2496 | dma_release_channel(pcdev->dma_chans[2]); |
1831 | 2497 | ||
1832 | soc_camera_host_unregister(soc_host); | 2498 | v4l2_clk_unregister(pcdev->mclk_clk); |
2499 | v4l2_device_unregister(&pcdev->v4l2_dev); | ||
1833 | 2500 | ||
1834 | dev_info(&pdev->dev, "PXA Camera driver unloaded\n"); | 2501 | dev_info(&pdev->dev, "PXA Camera driver unloaded\n"); |
1835 | 2502 | ||
diff --git a/drivers/media/platform/rcar-fcp.c b/drivers/media/platform/rcar-fcp.c index bc50c69ee0c5..f3a3f31cdfa9 100644 --- a/drivers/media/platform/rcar-fcp.c +++ b/drivers/media/platform/rcar-fcp.c | |||
@@ -99,14 +99,14 @@ EXPORT_SYMBOL_GPL(rcar_fcp_put); | |||
99 | */ | 99 | */ |
100 | int rcar_fcp_enable(struct rcar_fcp_device *fcp) | 100 | int rcar_fcp_enable(struct rcar_fcp_device *fcp) |
101 | { | 101 | { |
102 | int error; | 102 | int ret; |
103 | 103 | ||
104 | if (!fcp) | 104 | if (!fcp) |
105 | return 0; | 105 | return 0; |
106 | 106 | ||
107 | error = pm_runtime_get_sync(fcp->dev); | 107 | ret = pm_runtime_get_sync(fcp->dev); |
108 | if (error < 0) | 108 | if (ret < 0) |
109 | return error; | 109 | return ret; |
110 | 110 | ||
111 | return 0; | 111 | return 0; |
112 | } | 112 | } |
@@ -165,6 +165,7 @@ static int rcar_fcp_remove(struct platform_device *pdev) | |||
165 | } | 165 | } |
166 | 166 | ||
167 | static const struct of_device_id rcar_fcp_of_match[] = { | 167 | static const struct of_device_id rcar_fcp_of_match[] = { |
168 | { .compatible = "renesas,fcpf" }, | ||
168 | { .compatible = "renesas,fcpv" }, | 169 | { .compatible = "renesas,fcpv" }, |
169 | { }, | 170 | { }, |
170 | }; | 171 | }; |
diff --git a/drivers/media/platform/rcar-vin/Kconfig b/drivers/media/platform/rcar-vin/Kconfig index b2ff2d4e8bb1..111d2a151f6a 100644 --- a/drivers/media/platform/rcar-vin/Kconfig +++ b/drivers/media/platform/rcar-vin/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config VIDEO_RCAR_VIN | 1 | config VIDEO_RCAR_VIN |
2 | tristate "R-Car Video Input (VIN) Driver" | 2 | tristate "R-Car Video Input (VIN) Driver" |
3 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA | 3 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA && MEDIA_CONTROLLER |
4 | depends on ARCH_RENESAS || COMPILE_TEST | 4 | depends on ARCH_RENESAS || COMPILE_TEST |
5 | select VIDEOBUF2_DMA_CONTIG | 5 | select VIDEOBUF2_DMA_CONTIG |
6 | ---help--- | 6 | ---help--- |
diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 4b2007b73463..098a0b1cc10a 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c | |||
@@ -31,26 +31,22 @@ | |||
31 | 31 | ||
32 | #define notifier_to_vin(n) container_of(n, struct rvin_dev, notifier) | 32 | #define notifier_to_vin(n) container_of(n, struct rvin_dev, notifier) |
33 | 33 | ||
34 | static int rvin_mbus_supported(struct rvin_dev *vin) | 34 | static bool rvin_mbus_supported(struct rvin_graph_entity *entity) |
35 | { | 35 | { |
36 | struct v4l2_subdev *sd; | 36 | struct v4l2_subdev *sd = entity->subdev; |
37 | struct v4l2_subdev_mbus_code_enum code = { | 37 | struct v4l2_subdev_mbus_code_enum code = { |
38 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | 38 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
39 | }; | 39 | }; |
40 | 40 | ||
41 | sd = vin_to_source(vin); | ||
42 | |||
43 | code.index = 0; | 41 | code.index = 0; |
44 | while (!v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code)) { | 42 | while (!v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code)) { |
45 | code.index++; | 43 | code.index++; |
46 | switch (code.code) { | 44 | switch (code.code) { |
47 | case MEDIA_BUS_FMT_YUYV8_1X16: | 45 | case MEDIA_BUS_FMT_YUYV8_1X16: |
48 | case MEDIA_BUS_FMT_YUYV8_2X8: | 46 | case MEDIA_BUS_FMT_UYVY8_2X8: |
49 | case MEDIA_BUS_FMT_YUYV10_2X10: | 47 | case MEDIA_BUS_FMT_UYVY10_2X10: |
50 | case MEDIA_BUS_FMT_RGB888_1X24: | 48 | case MEDIA_BUS_FMT_RGB888_1X24: |
51 | vin->source.code = code.code; | 49 | entity->code = code.code; |
52 | vin_dbg(vin, "Found supported media bus format: %d\n", | ||
53 | vin->source.code); | ||
54 | return true; | 50 | return true; |
55 | default: | 51 | default: |
56 | break; | 52 | break; |
@@ -60,142 +56,168 @@ static int rvin_mbus_supported(struct rvin_dev *vin) | |||
60 | return false; | 56 | return false; |
61 | } | 57 | } |
62 | 58 | ||
63 | static int rvin_graph_notify_complete(struct v4l2_async_notifier *notifier) | 59 | static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier) |
64 | { | 60 | { |
65 | struct rvin_dev *vin = notifier_to_vin(notifier); | 61 | struct rvin_dev *vin = notifier_to_vin(notifier); |
66 | int ret; | 62 | int ret; |
67 | 63 | ||
64 | /* Verify subdevices mbus format */ | ||
65 | if (!rvin_mbus_supported(&vin->digital)) { | ||
66 | vin_err(vin, "Unsupported media bus format for %s\n", | ||
67 | vin->digital.subdev->name); | ||
68 | return -EINVAL; | ||
69 | } | ||
70 | |||
71 | vin_dbg(vin, "Found media bus format for %s: %d\n", | ||
72 | vin->digital.subdev->name, vin->digital.code); | ||
73 | |||
68 | ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev); | 74 | ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev); |
69 | if (ret < 0) { | 75 | if (ret < 0) { |
70 | vin_err(vin, "Failed to register subdev nodes\n"); | 76 | vin_err(vin, "Failed to register subdev nodes\n"); |
71 | return ret; | 77 | return ret; |
72 | } | 78 | } |
73 | 79 | ||
74 | if (!rvin_mbus_supported(vin)) { | 80 | return rvin_v4l2_probe(vin); |
75 | vin_err(vin, "No supported mediabus format found\n"); | 81 | } |
76 | return -EINVAL; | 82 | |
83 | static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier, | ||
84 | struct v4l2_subdev *subdev, | ||
85 | struct v4l2_async_subdev *asd) | ||
86 | { | ||
87 | struct rvin_dev *vin = notifier_to_vin(notifier); | ||
88 | |||
89 | if (vin->digital.subdev == subdev) { | ||
90 | vin_dbg(vin, "unbind digital subdev %s\n", subdev->name); | ||
91 | rvin_v4l2_remove(vin); | ||
92 | vin->digital.subdev = NULL; | ||
93 | return; | ||
77 | } | 94 | } |
78 | 95 | ||
79 | return rvin_v4l2_probe(vin); | 96 | vin_err(vin, "no entity for subdev %s to unbind\n", subdev->name); |
80 | } | 97 | } |
81 | 98 | ||
82 | static void rvin_graph_notify_unbind(struct v4l2_async_notifier *notifier, | 99 | static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, |
83 | struct v4l2_subdev *sd, | 100 | struct v4l2_subdev *subdev, |
84 | struct v4l2_async_subdev *asd) | 101 | struct v4l2_async_subdev *asd) |
85 | { | 102 | { |
86 | struct rvin_dev *vin = notifier_to_vin(notifier); | 103 | struct rvin_dev *vin = notifier_to_vin(notifier); |
87 | 104 | ||
88 | rvin_v4l2_remove(vin); | 105 | v4l2_set_subdev_hostdata(subdev, vin); |
106 | |||
107 | if (vin->digital.asd.match.of.node == subdev->dev->of_node) { | ||
108 | vin_dbg(vin, "bound digital subdev %s\n", subdev->name); | ||
109 | vin->digital.subdev = subdev; | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | vin_err(vin, "no entity for subdev %s to bind\n", subdev->name); | ||
114 | return -EINVAL; | ||
89 | } | 115 | } |
90 | 116 | ||
91 | static int rvin_graph_notify_bound(struct v4l2_async_notifier *notifier, | 117 | static int rvin_digitial_parse_v4l2(struct rvin_dev *vin, |
92 | struct v4l2_subdev *subdev, | 118 | struct device_node *ep, |
93 | struct v4l2_async_subdev *asd) | 119 | struct v4l2_mbus_config *mbus_cfg) |
94 | { | 120 | { |
95 | struct rvin_dev *vin = notifier_to_vin(notifier); | 121 | struct v4l2_of_endpoint v4l2_ep; |
122 | int ret; | ||
96 | 123 | ||
97 | vin_dbg(vin, "subdev %s bound\n", subdev->name); | 124 | ret = v4l2_of_parse_endpoint(ep, &v4l2_ep); |
125 | if (ret) { | ||
126 | vin_err(vin, "Could not parse v4l2 endpoint\n"); | ||
127 | return -EINVAL; | ||
128 | } | ||
98 | 129 | ||
99 | vin->entity.entity = &subdev->entity; | 130 | mbus_cfg->type = v4l2_ep.bus_type; |
100 | vin->entity.subdev = subdev; | 131 | |
132 | switch (mbus_cfg->type) { | ||
133 | case V4L2_MBUS_PARALLEL: | ||
134 | vin_dbg(vin, "Found PARALLEL media bus\n"); | ||
135 | mbus_cfg->flags = v4l2_ep.bus.parallel.flags; | ||
136 | break; | ||
137 | case V4L2_MBUS_BT656: | ||
138 | vin_dbg(vin, "Found BT656 media bus\n"); | ||
139 | mbus_cfg->flags = 0; | ||
140 | break; | ||
141 | default: | ||
142 | vin_err(vin, "Unknown media bus type\n"); | ||
143 | return -EINVAL; | ||
144 | } | ||
101 | 145 | ||
102 | return 0; | 146 | return 0; |
103 | } | 147 | } |
104 | 148 | ||
105 | static int rvin_graph_parse(struct rvin_dev *vin, | 149 | static int rvin_digital_graph_parse(struct rvin_dev *vin) |
106 | struct device_node *node) | ||
107 | { | 150 | { |
108 | struct device_node *remote; | 151 | struct device_node *ep, *np; |
109 | struct device_node *ep = NULL; | 152 | int ret; |
110 | struct device_node *next; | ||
111 | int ret = 0; | ||
112 | |||
113 | while (1) { | ||
114 | next = of_graph_get_next_endpoint(node, ep); | ||
115 | if (!next) | ||
116 | break; | ||
117 | |||
118 | of_node_put(ep); | ||
119 | ep = next; | ||
120 | 153 | ||
121 | remote = of_graph_get_remote_port_parent(ep); | 154 | vin->digital.asd.match.of.node = NULL; |
122 | if (!remote) { | 155 | vin->digital.subdev = NULL; |
123 | ret = -EINVAL; | ||
124 | break; | ||
125 | } | ||
126 | 156 | ||
127 | /* Skip entities that we have already processed. */ | 157 | /* |
128 | if (remote == vin->dev->of_node) { | 158 | * Port 0 id 0 is local digital input, try to get it. |
129 | of_node_put(remote); | 159 | * Not all instances can or will have this, that is OK |
130 | continue; | 160 | */ |
131 | } | 161 | ep = of_graph_get_endpoint_by_regs(vin->dev->of_node, 0, 0); |
162 | if (!ep) | ||
163 | return 0; | ||
132 | 164 | ||
133 | /* Remote node to connect */ | 165 | np = of_graph_get_remote_port_parent(ep); |
134 | if (!vin->entity.node) { | 166 | if (!np) { |
135 | vin->entity.node = remote; | 167 | vin_err(vin, "No remote parent for digital input\n"); |
136 | vin->entity.asd.match_type = V4L2_ASYNC_MATCH_OF; | 168 | of_node_put(ep); |
137 | vin->entity.asd.match.of.node = remote; | 169 | return -EINVAL; |
138 | ret++; | ||
139 | } | ||
140 | } | 170 | } |
171 | of_node_put(np); | ||
141 | 172 | ||
173 | ret = rvin_digitial_parse_v4l2(vin, ep, &vin->digital.mbus_cfg); | ||
142 | of_node_put(ep); | 174 | of_node_put(ep); |
175 | if (ret) | ||
176 | return ret; | ||
143 | 177 | ||
144 | return ret; | 178 | vin->digital.asd.match.of.node = np; |
179 | vin->digital.asd.match_type = V4L2_ASYNC_MATCH_OF; | ||
180 | |||
181 | return 0; | ||
145 | } | 182 | } |
146 | 183 | ||
147 | static int rvin_graph_init(struct rvin_dev *vin) | 184 | static int rvin_digital_graph_init(struct rvin_dev *vin) |
148 | { | 185 | { |
149 | struct v4l2_async_subdev **subdevs = NULL; | 186 | struct v4l2_async_subdev **subdevs = NULL; |
150 | int ret; | 187 | int ret; |
151 | 188 | ||
152 | /* Parse the graph to extract a list of subdevice DT nodes. */ | 189 | ret = rvin_digital_graph_parse(vin); |
153 | ret = rvin_graph_parse(vin, vin->dev->of_node); | 190 | if (ret) |
154 | if (ret < 0) { | 191 | return ret; |
155 | vin_err(vin, "Graph parsing failed\n"); | ||
156 | goto done; | ||
157 | } | ||
158 | |||
159 | if (!ret) { | ||
160 | vin_err(vin, "No subdev found in graph\n"); | ||
161 | goto done; | ||
162 | } | ||
163 | 192 | ||
164 | if (ret != 1) { | 193 | if (!vin->digital.asd.match.of.node) { |
165 | vin_err(vin, "More then one subdev found in graph\n"); | 194 | vin_dbg(vin, "No digital subdevice found\n"); |
166 | goto done; | 195 | return -ENODEV; |
167 | } | 196 | } |
168 | 197 | ||
169 | /* Register the subdevices notifier. */ | 198 | /* Register the subdevices notifier. */ |
170 | subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL); | 199 | subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL); |
171 | if (subdevs == NULL) { | 200 | if (subdevs == NULL) |
172 | ret = -ENOMEM; | 201 | return -ENOMEM; |
173 | goto done; | ||
174 | } | ||
175 | 202 | ||
176 | subdevs[0] = &vin->entity.asd; | 203 | subdevs[0] = &vin->digital.asd; |
204 | |||
205 | vin_dbg(vin, "Found digital subdevice %s\n", | ||
206 | of_node_full_name(subdevs[0]->match.of.node)); | ||
177 | 207 | ||
178 | vin->notifier.subdevs = subdevs; | ||
179 | vin->notifier.num_subdevs = 1; | 208 | vin->notifier.num_subdevs = 1; |
180 | vin->notifier.bound = rvin_graph_notify_bound; | 209 | vin->notifier.subdevs = subdevs; |
181 | vin->notifier.unbind = rvin_graph_notify_unbind; | 210 | vin->notifier.bound = rvin_digital_notify_bound; |
182 | vin->notifier.complete = rvin_graph_notify_complete; | 211 | vin->notifier.unbind = rvin_digital_notify_unbind; |
212 | vin->notifier.complete = rvin_digital_notify_complete; | ||
183 | 213 | ||
184 | ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier); | 214 | ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier); |
185 | if (ret < 0) { | 215 | if (ret < 0) { |
186 | vin_err(vin, "Notifier registration failed\n"); | 216 | vin_err(vin, "Notifier registration failed\n"); |
187 | goto done; | 217 | return ret; |
188 | } | ||
189 | |||
190 | ret = 0; | ||
191 | |||
192 | done: | ||
193 | if (ret < 0) { | ||
194 | v4l2_async_notifier_unregister(&vin->notifier); | ||
195 | of_node_put(vin->entity.node); | ||
196 | } | 218 | } |
197 | 219 | ||
198 | return ret; | 220 | return 0; |
199 | } | 221 | } |
200 | 222 | ||
201 | /* ----------------------------------------------------------------------------- | 223 | /* ----------------------------------------------------------------------------- |
@@ -209,56 +231,14 @@ static const struct of_device_id rvin_of_id_table[] = { | |||
209 | { .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 }, | 231 | { .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 }, |
210 | { .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 }, | 232 | { .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 }, |
211 | { .compatible = "renesas,vin-r8a7778", .data = (void *)RCAR_M1 }, | 233 | { .compatible = "renesas,vin-r8a7778", .data = (void *)RCAR_M1 }, |
234 | { .compatible = "renesas,rcar-gen2-vin", .data = (void *)RCAR_GEN2 }, | ||
212 | { }, | 235 | { }, |
213 | }; | 236 | }; |
214 | MODULE_DEVICE_TABLE(of, rvin_of_id_table); | 237 | MODULE_DEVICE_TABLE(of, rvin_of_id_table); |
215 | 238 | ||
216 | static int rvin_parse_dt(struct rvin_dev *vin) | ||
217 | { | ||
218 | const struct of_device_id *match; | ||
219 | struct v4l2_of_endpoint ep; | ||
220 | struct device_node *np; | ||
221 | int ret; | ||
222 | |||
223 | match = of_match_device(of_match_ptr(rvin_of_id_table), vin->dev); | ||
224 | if (!match) | ||
225 | return -ENODEV; | ||
226 | |||
227 | vin->chip = (enum chip_id)match->data; | ||
228 | |||
229 | np = of_graph_get_next_endpoint(vin->dev->of_node, NULL); | ||
230 | if (!np) { | ||
231 | vin_err(vin, "Could not find endpoint\n"); | ||
232 | return -EINVAL; | ||
233 | } | ||
234 | |||
235 | ret = v4l2_of_parse_endpoint(np, &ep); | ||
236 | if (ret) { | ||
237 | vin_err(vin, "Could not parse endpoint\n"); | ||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | of_node_put(np); | ||
242 | |||
243 | vin->mbus_cfg.type = ep.bus_type; | ||
244 | |||
245 | switch (vin->mbus_cfg.type) { | ||
246 | case V4L2_MBUS_PARALLEL: | ||
247 | vin->mbus_cfg.flags = ep.bus.parallel.flags; | ||
248 | break; | ||
249 | case V4L2_MBUS_BT656: | ||
250 | vin->mbus_cfg.flags = 0; | ||
251 | break; | ||
252 | default: | ||
253 | vin_err(vin, "Unknown media bus type\n"); | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static int rcar_vin_probe(struct platform_device *pdev) | 239 | static int rcar_vin_probe(struct platform_device *pdev) |
261 | { | 240 | { |
241 | const struct of_device_id *match; | ||
262 | struct rvin_dev *vin; | 242 | struct rvin_dev *vin; |
263 | struct resource *mem; | 243 | struct resource *mem; |
264 | int irq, ret; | 244 | int irq, ret; |
@@ -267,11 +247,12 @@ static int rcar_vin_probe(struct platform_device *pdev) | |||
267 | if (!vin) | 247 | if (!vin) |
268 | return -ENOMEM; | 248 | return -ENOMEM; |
269 | 249 | ||
270 | vin->dev = &pdev->dev; | 250 | match = of_match_device(of_match_ptr(rvin_of_id_table), &pdev->dev); |
251 | if (!match) | ||
252 | return -ENODEV; | ||
271 | 253 | ||
272 | ret = rvin_parse_dt(vin); | 254 | vin->dev = &pdev->dev; |
273 | if (ret) | 255 | vin->chip = (enum chip_id)match->data; |
274 | return ret; | ||
275 | 256 | ||
276 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 257 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
277 | if (mem == NULL) | 258 | if (mem == NULL) |
@@ -282,14 +263,14 @@ static int rcar_vin_probe(struct platform_device *pdev) | |||
282 | return PTR_ERR(vin->base); | 263 | return PTR_ERR(vin->base); |
283 | 264 | ||
284 | irq = platform_get_irq(pdev, 0); | 265 | irq = platform_get_irq(pdev, 0); |
285 | if (irq <= 0) | 266 | if (irq < 0) |
286 | return ret; | 267 | return irq; |
287 | 268 | ||
288 | ret = rvin_dma_probe(vin, irq); | 269 | ret = rvin_dma_probe(vin, irq); |
289 | if (ret) | 270 | if (ret) |
290 | return ret; | 271 | return ret; |
291 | 272 | ||
292 | ret = rvin_graph_init(vin); | 273 | ret = rvin_digital_graph_init(vin); |
293 | if (ret < 0) | 274 | if (ret < 0) |
294 | goto error; | 275 | goto error; |
295 | 276 | ||
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 496aa97b6400..9ccd5ff55e19 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c | |||
@@ -95,6 +95,7 @@ | |||
95 | /* Video n Module Status Register bits */ | 95 | /* Video n Module Status Register bits */ |
96 | #define VNMS_FBS_MASK (3 << 3) | 96 | #define VNMS_FBS_MASK (3 << 3) |
97 | #define VNMS_FBS_SHIFT 3 | 97 | #define VNMS_FBS_SHIFT 3 |
98 | #define VNMS_FS (1 << 2) | ||
98 | #define VNMS_AV (1 << 1) | 99 | #define VNMS_AV (1 << 1) |
99 | #define VNMS_CA (1 << 0) | 100 | #define VNMS_CA (1 << 0) |
100 | 101 | ||
@@ -131,6 +132,7 @@ static u32 rvin_read(struct rvin_dev *vin, u32 offset) | |||
131 | static int rvin_setup(struct rvin_dev *vin) | 132 | static int rvin_setup(struct rvin_dev *vin) |
132 | { | 133 | { |
133 | u32 vnmc, dmr, dmr2, interrupts; | 134 | u32 vnmc, dmr, dmr2, interrupts; |
135 | v4l2_std_id std; | ||
134 | bool progressive = false, output_is_yuv = false, input_is_yuv = false; | 136 | bool progressive = false, output_is_yuv = false, input_is_yuv = false; |
135 | 137 | ||
136 | switch (vin->format.field) { | 138 | switch (vin->format.field) { |
@@ -141,12 +143,21 @@ static int rvin_setup(struct rvin_dev *vin) | |||
141 | vnmc = VNMC_IM_EVEN; | 143 | vnmc = VNMC_IM_EVEN; |
142 | break; | 144 | break; |
143 | case V4L2_FIELD_INTERLACED: | 145 | case V4L2_FIELD_INTERLACED: |
146 | /* Default to TB */ | ||
147 | vnmc = VNMC_IM_FULL; | ||
148 | /* Use BT if video standard can be read and is 60 Hz format */ | ||
149 | if (!v4l2_subdev_call(vin_to_source(vin), video, g_std, &std)) { | ||
150 | if (std & V4L2_STD_525_60) | ||
151 | vnmc = VNMC_IM_FULL | VNMC_FOC; | ||
152 | } | ||
153 | break; | ||
144 | case V4L2_FIELD_INTERLACED_TB: | 154 | case V4L2_FIELD_INTERLACED_TB: |
145 | vnmc = VNMC_IM_FULL; | 155 | vnmc = VNMC_IM_FULL; |
146 | break; | 156 | break; |
147 | case V4L2_FIELD_INTERLACED_BT: | 157 | case V4L2_FIELD_INTERLACED_BT: |
148 | vnmc = VNMC_IM_FULL | VNMC_FOC; | 158 | vnmc = VNMC_IM_FULL | VNMC_FOC; |
149 | break; | 159 | break; |
160 | case V4L2_FIELD_ALTERNATE: | ||
150 | case V4L2_FIELD_NONE: | 161 | case V4L2_FIELD_NONE: |
151 | if (vin->continuous) { | 162 | if (vin->continuous) { |
152 | vnmc = VNMC_IM_ODD_EVEN; | 163 | vnmc = VNMC_IM_ODD_EVEN; |
@@ -163,24 +174,24 @@ static int rvin_setup(struct rvin_dev *vin) | |||
163 | /* | 174 | /* |
164 | * Input interface | 175 | * Input interface |
165 | */ | 176 | */ |
166 | switch (vin->source.code) { | 177 | switch (vin->digital.code) { |
167 | case MEDIA_BUS_FMT_YUYV8_1X16: | 178 | case MEDIA_BUS_FMT_YUYV8_1X16: |
168 | /* BT.601/BT.1358 16bit YCbCr422 */ | 179 | /* BT.601/BT.1358 16bit YCbCr422 */ |
169 | vnmc |= VNMC_INF_YUV16; | 180 | vnmc |= VNMC_INF_YUV16; |
170 | input_is_yuv = true; | 181 | input_is_yuv = true; |
171 | break; | 182 | break; |
172 | case MEDIA_BUS_FMT_YUYV8_2X8: | 183 | case MEDIA_BUS_FMT_UYVY8_2X8: |
173 | /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ | 184 | /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ |
174 | vnmc |= vin->mbus_cfg.type == V4L2_MBUS_BT656 ? | 185 | vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ? |
175 | VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601; | 186 | VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601; |
176 | input_is_yuv = true; | 187 | input_is_yuv = true; |
177 | break; | 188 | break; |
178 | case MEDIA_BUS_FMT_RGB888_1X24: | 189 | case MEDIA_BUS_FMT_RGB888_1X24: |
179 | vnmc |= VNMC_INF_RGB888; | 190 | vnmc |= VNMC_INF_RGB888; |
180 | break; | 191 | break; |
181 | case MEDIA_BUS_FMT_YUYV10_2X10: | 192 | case MEDIA_BUS_FMT_UYVY10_2X10: |
182 | /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ | 193 | /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ |
183 | vnmc |= vin->mbus_cfg.type == V4L2_MBUS_BT656 ? | 194 | vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ? |
184 | VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601; | 195 | VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601; |
185 | input_is_yuv = true; | 196 | input_is_yuv = true; |
186 | break; | 197 | break; |
@@ -192,11 +203,11 @@ static int rvin_setup(struct rvin_dev *vin) | |||
192 | dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1); | 203 | dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1); |
193 | 204 | ||
194 | /* Hsync Signal Polarity Select */ | 205 | /* Hsync Signal Polarity Select */ |
195 | if (!(vin->mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) | 206 | if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) |
196 | dmr2 |= VNDMR2_HPS; | 207 | dmr2 |= VNDMR2_HPS; |
197 | 208 | ||
198 | /* Vsync Signal Polarity Select */ | 209 | /* Vsync Signal Polarity Select */ |
199 | if (!(vin->mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) | 210 | if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) |
200 | dmr2 |= VNDMR2_VPS; | 211 | dmr2 |= VNDMR2_VPS; |
201 | 212 | ||
202 | /* | 213 | /* |
@@ -225,11 +236,9 @@ static int rvin_setup(struct rvin_dev *vin) | |||
225 | dmr = 0; | 236 | dmr = 0; |
226 | break; | 237 | break; |
227 | case V4L2_PIX_FMT_XBGR32: | 238 | case V4L2_PIX_FMT_XBGR32: |
228 | if (vin->chip == RCAR_GEN2 || vin->chip == RCAR_H1) { | 239 | /* Note: not supported on M1 */ |
229 | dmr = VNDMR_EXRGB; | 240 | dmr = VNDMR_EXRGB; |
230 | break; | 241 | break; |
231 | } | ||
232 | /* fall through */ | ||
233 | default: | 242 | default: |
234 | vin_err(vin, "Invalid pixelformat (0x%x)\n", | 243 | vin_err(vin, "Invalid pixelformat (0x%x)\n", |
235 | vin->format.pixelformat); | 244 | vin->format.pixelformat); |
@@ -322,15 +331,26 @@ static bool rvin_capture_active(struct rvin_dev *vin) | |||
322 | return rvin_read(vin, VNMS_REG) & VNMS_CA; | 331 | return rvin_read(vin, VNMS_REG) & VNMS_CA; |
323 | } | 332 | } |
324 | 333 | ||
325 | static int rvin_get_active_slot(struct rvin_dev *vin) | 334 | static int rvin_get_active_slot(struct rvin_dev *vin, u32 vnms) |
326 | { | 335 | { |
327 | if (vin->continuous) | 336 | if (vin->continuous) |
328 | return (rvin_read(vin, VNMS_REG) & VNMS_FBS_MASK) | 337 | return (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT; |
329 | >> VNMS_FBS_SHIFT; | ||
330 | 338 | ||
331 | return 0; | 339 | return 0; |
332 | } | 340 | } |
333 | 341 | ||
342 | static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms) | ||
343 | { | ||
344 | if (vin->format.field == V4L2_FIELD_ALTERNATE) { | ||
345 | /* If FS is set it's a Even field */ | ||
346 | if (vnms & VNMS_FS) | ||
347 | return V4L2_FIELD_BOTTOM; | ||
348 | return V4L2_FIELD_TOP; | ||
349 | } | ||
350 | |||
351 | return vin->format.field; | ||
352 | } | ||
353 | |||
334 | static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr) | 354 | static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr) |
335 | { | 355 | { |
336 | const struct rvin_video_format *fmt; | 356 | const struct rvin_video_format *fmt; |
@@ -871,7 +891,7 @@ static bool rvin_fill_hw(struct rvin_dev *vin) | |||
871 | static irqreturn_t rvin_irq(int irq, void *data) | 891 | static irqreturn_t rvin_irq(int irq, void *data) |
872 | { | 892 | { |
873 | struct rvin_dev *vin = data; | 893 | struct rvin_dev *vin = data; |
874 | u32 int_status; | 894 | u32 int_status, vnms; |
875 | int slot; | 895 | int slot; |
876 | unsigned int sequence, handled = 0; | 896 | unsigned int sequence, handled = 0; |
877 | unsigned long flags; | 897 | unsigned long flags; |
@@ -898,7 +918,8 @@ static irqreturn_t rvin_irq(int irq, void *data) | |||
898 | } | 918 | } |
899 | 919 | ||
900 | /* Prepare for capture and update state */ | 920 | /* Prepare for capture and update state */ |
901 | slot = rvin_get_active_slot(vin); | 921 | vnms = rvin_read(vin, VNMS_REG); |
922 | slot = rvin_get_active_slot(vin, vnms); | ||
902 | sequence = vin->sequence++; | 923 | sequence = vin->sequence++; |
903 | 924 | ||
904 | vin_dbg(vin, "IRQ %02d: %d\tbuf0: %c buf1: %c buf2: %c\tmore: %d\n", | 925 | vin_dbg(vin, "IRQ %02d: %d\tbuf0: %c buf1: %c buf2: %c\tmore: %d\n", |
@@ -913,7 +934,7 @@ static irqreturn_t rvin_irq(int irq, void *data) | |||
913 | goto done; | 934 | goto done; |
914 | 935 | ||
915 | /* Capture frame */ | 936 | /* Capture frame */ |
916 | vin->queue_buf[slot]->field = vin->format.field; | 937 | vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms); |
917 | vin->queue_buf[slot]->sequence = sequence; | 938 | vin->queue_buf[slot]->sequence = sequence; |
918 | vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); | 939 | vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); |
919 | vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, VB2_BUF_STATE_DONE); | 940 | vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, VB2_BUF_STATE_DONE); |
@@ -1116,7 +1137,7 @@ static void rvin_stop_streaming(struct vb2_queue *vq) | |||
1116 | rvin_disable_interrupts(vin); | 1137 | rvin_disable_interrupts(vin); |
1117 | } | 1138 | } |
1118 | 1139 | ||
1119 | static struct vb2_ops rvin_qops = { | 1140 | static const struct vb2_ops rvin_qops = { |
1120 | .queue_setup = rvin_queue_setup, | 1141 | .queue_setup = rvin_queue_setup, |
1121 | .buf_prepare = rvin_buffer_prepare, | 1142 | .buf_prepare = rvin_buffer_prepare, |
1122 | .buf_queue = rvin_buffer_queue, | 1143 | .buf_queue = rvin_buffer_queue, |
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index 10a5c107e8b9..2bbe6d495fa6 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c | |||
@@ -92,21 +92,84 @@ static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix) | |||
92 | * V4L2 | 92 | * V4L2 |
93 | */ | 93 | */ |
94 | 94 | ||
95 | static void rvin_reset_crop_compose(struct rvin_dev *vin) | ||
96 | { | ||
97 | vin->crop.top = vin->crop.left = 0; | ||
98 | vin->crop.width = vin->source.width; | ||
99 | vin->crop.height = vin->source.height; | ||
100 | |||
101 | vin->compose.top = vin->compose.left = 0; | ||
102 | vin->compose.width = vin->format.width; | ||
103 | vin->compose.height = vin->format.height; | ||
104 | } | ||
105 | |||
106 | static int rvin_reset_format(struct rvin_dev *vin) | ||
107 | { | ||
108 | struct v4l2_subdev_format fmt = { | ||
109 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
110 | }; | ||
111 | struct v4l2_mbus_framefmt *mf = &fmt.format; | ||
112 | int ret; | ||
113 | |||
114 | fmt.pad = vin->src_pad_idx; | ||
115 | |||
116 | ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt); | ||
117 | if (ret) | ||
118 | return ret; | ||
119 | |||
120 | vin->format.width = mf->width; | ||
121 | vin->format.height = mf->height; | ||
122 | vin->format.colorspace = mf->colorspace; | ||
123 | vin->format.field = mf->field; | ||
124 | |||
125 | /* | ||
126 | * If the subdevice uses ALTERNATE field mode and G_STD is | ||
127 | * implemented use the VIN HW to combine the two fields to | ||
128 | * one INTERLACED frame. The ALTERNATE field mode can still | ||
129 | * be requested in S_FMT and be respected, this is just the | ||
130 | * default which is applied at probing or when S_STD is called. | ||
131 | */ | ||
132 | if (vin->format.field == V4L2_FIELD_ALTERNATE && | ||
133 | v4l2_subdev_has_op(vin_to_source(vin), video, g_std)) | ||
134 | vin->format.field = V4L2_FIELD_INTERLACED; | ||
135 | |||
136 | switch (vin->format.field) { | ||
137 | case V4L2_FIELD_TOP: | ||
138 | case V4L2_FIELD_BOTTOM: | ||
139 | case V4L2_FIELD_ALTERNATE: | ||
140 | vin->format.height /= 2; | ||
141 | break; | ||
142 | case V4L2_FIELD_NONE: | ||
143 | case V4L2_FIELD_INTERLACED_TB: | ||
144 | case V4L2_FIELD_INTERLACED_BT: | ||
145 | case V4L2_FIELD_INTERLACED: | ||
146 | break; | ||
147 | default: | ||
148 | vin->format.field = V4L2_FIELD_NONE; | ||
149 | break; | ||
150 | } | ||
151 | |||
152 | rvin_reset_crop_compose(vin); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
95 | static int __rvin_try_format_source(struct rvin_dev *vin, | 157 | static int __rvin_try_format_source(struct rvin_dev *vin, |
96 | u32 which, | 158 | u32 which, |
97 | struct v4l2_pix_format *pix, | 159 | struct v4l2_pix_format *pix, |
98 | struct rvin_source_fmt *source) | 160 | struct rvin_source_fmt *source) |
99 | { | 161 | { |
100 | struct v4l2_subdev *sd; | 162 | struct v4l2_subdev *sd; |
101 | struct v4l2_subdev_pad_config *pad_cfg; | 163 | struct v4l2_subdev_pad_config *pad_cfg; |
102 | struct v4l2_subdev_format format = { | 164 | struct v4l2_subdev_format format = { |
103 | .which = which, | 165 | .which = which, |
104 | }; | 166 | }; |
167 | enum v4l2_field field; | ||
105 | int ret; | 168 | int ret; |
106 | 169 | ||
107 | sd = vin_to_source(vin); | 170 | sd = vin_to_source(vin); |
108 | 171 | ||
109 | v4l2_fill_mbus_format(&format.format, pix, vin->source.code); | 172 | v4l2_fill_mbus_format(&format.format, pix, vin->digital.code); |
110 | 173 | ||
111 | pad_cfg = v4l2_subdev_alloc_pad_config(sd); | 174 | pad_cfg = v4l2_subdev_alloc_pad_config(sd); |
112 | if (pad_cfg == NULL) | 175 | if (pad_cfg == NULL) |
@@ -114,28 +177,31 @@ static int __rvin_try_format_source(struct rvin_dev *vin, | |||
114 | 177 | ||
115 | format.pad = vin->src_pad_idx; | 178 | format.pad = vin->src_pad_idx; |
116 | 179 | ||
117 | ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, pad, set_fmt, | 180 | field = pix->field; |
118 | pad_cfg, &format); | 181 | |
119 | if (ret < 0) | 182 | ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format); |
120 | goto cleanup; | 183 | if (ret < 0 && ret != -ENOIOCTLCMD) |
184 | goto done; | ||
121 | 185 | ||
122 | v4l2_fill_pix_format(pix, &format.format); | 186 | v4l2_fill_pix_format(pix, &format.format); |
123 | 187 | ||
188 | pix->field = field; | ||
189 | |||
124 | source->width = pix->width; | 190 | source->width = pix->width; |
125 | source->height = pix->height; | 191 | source->height = pix->height; |
126 | 192 | ||
127 | vin_dbg(vin, "Source resolution: %ux%u\n", source->width, | 193 | vin_dbg(vin, "Source resolution: %ux%u\n", source->width, |
128 | source->height); | 194 | source->height); |
129 | 195 | ||
130 | cleanup: | 196 | done: |
131 | v4l2_subdev_free_pad_config(pad_cfg); | 197 | v4l2_subdev_free_pad_config(pad_cfg); |
132 | return 0; | 198 | return ret; |
133 | } | 199 | } |
134 | 200 | ||
135 | static int __rvin_try_format(struct rvin_dev *vin, | 201 | static int __rvin_try_format(struct rvin_dev *vin, |
136 | u32 which, | 202 | u32 which, |
137 | struct v4l2_pix_format *pix, | 203 | struct v4l2_pix_format *pix, |
138 | struct rvin_source_fmt *source) | 204 | struct rvin_source_fmt *source) |
139 | { | 205 | { |
140 | const struct rvin_video_format *info; | 206 | const struct rvin_video_format *info; |
141 | u32 rwidth, rheight, walign; | 207 | u32 rwidth, rheight, walign; |
@@ -144,6 +210,10 @@ static int __rvin_try_format(struct rvin_dev *vin, | |||
144 | rwidth = pix->width; | 210 | rwidth = pix->width; |
145 | rheight = pix->height; | 211 | rheight = pix->height; |
146 | 212 | ||
213 | /* Keep current field if no specific one is asked for */ | ||
214 | if (pix->field == V4L2_FIELD_ANY) | ||
215 | pix->field = vin->format.field; | ||
216 | |||
147 | /* | 217 | /* |
148 | * Retrieve format information and select the current format if the | 218 | * Retrieve format information and select the current format if the |
149 | * requested format isn't supported. | 219 | * requested format isn't supported. |
@@ -164,21 +234,14 @@ static int __rvin_try_format(struct rvin_dev *vin, | |||
164 | /* Limit to source capabilities */ | 234 | /* Limit to source capabilities */ |
165 | __rvin_try_format_source(vin, which, pix, source); | 235 | __rvin_try_format_source(vin, which, pix, source); |
166 | 236 | ||
167 | /* If source can't match format try if VIN can scale */ | ||
168 | if (source->width != rwidth || source->height != rheight) | ||
169 | rvin_scale_try(vin, pix, rwidth, rheight); | ||
170 | |||
171 | /* HW limit width to a multiple of 32 (2^5) for NV16 else 2 (2^1) */ | ||
172 | walign = vin->format.pixelformat == V4L2_PIX_FMT_NV16 ? 5 : 1; | ||
173 | |||
174 | /* Limit to VIN capabilities */ | ||
175 | v4l_bound_align_image(&pix->width, 2, RVIN_MAX_WIDTH, walign, | ||
176 | &pix->height, 4, RVIN_MAX_HEIGHT, 2, 0); | ||
177 | |||
178 | switch (pix->field) { | 237 | switch (pix->field) { |
179 | case V4L2_FIELD_NONE: | ||
180 | case V4L2_FIELD_TOP: | 238 | case V4L2_FIELD_TOP: |
181 | case V4L2_FIELD_BOTTOM: | 239 | case V4L2_FIELD_BOTTOM: |
240 | case V4L2_FIELD_ALTERNATE: | ||
241 | pix->height /= 2; | ||
242 | source->height /= 2; | ||
243 | break; | ||
244 | case V4L2_FIELD_NONE: | ||
182 | case V4L2_FIELD_INTERLACED_TB: | 245 | case V4L2_FIELD_INTERLACED_TB: |
183 | case V4L2_FIELD_INTERLACED_BT: | 246 | case V4L2_FIELD_INTERLACED_BT: |
184 | case V4L2_FIELD_INTERLACED: | 247 | case V4L2_FIELD_INTERLACED: |
@@ -188,11 +251,27 @@ static int __rvin_try_format(struct rvin_dev *vin, | |||
188 | break; | 251 | break; |
189 | } | 252 | } |
190 | 253 | ||
254 | /* If source can't match format try if VIN can scale */ | ||
255 | if (source->width != rwidth || source->height != rheight) | ||
256 | rvin_scale_try(vin, pix, rwidth, rheight); | ||
257 | |||
258 | /* HW limit width to a multiple of 32 (2^5) for NV16 else 2 (2^1) */ | ||
259 | walign = vin->format.pixelformat == V4L2_PIX_FMT_NV16 ? 5 : 1; | ||
260 | |||
261 | /* Limit to VIN capabilities */ | ||
262 | v4l_bound_align_image(&pix->width, 2, RVIN_MAX_WIDTH, walign, | ||
263 | &pix->height, 4, RVIN_MAX_HEIGHT, 2, 0); | ||
264 | |||
191 | pix->bytesperline = max_t(u32, pix->bytesperline, | 265 | pix->bytesperline = max_t(u32, pix->bytesperline, |
192 | rvin_format_bytesperline(pix)); | 266 | rvin_format_bytesperline(pix)); |
193 | pix->sizeimage = max_t(u32, pix->sizeimage, | 267 | pix->sizeimage = max_t(u32, pix->sizeimage, |
194 | rvin_format_sizeimage(pix)); | 268 | rvin_format_sizeimage(pix)); |
195 | 269 | ||
270 | if (vin->chip == RCAR_M1 && pix->pixelformat == V4L2_PIX_FMT_XBGR32) { | ||
271 | vin_err(vin, "pixel format XBGR32 not supported on M1\n"); | ||
272 | return -EINVAL; | ||
273 | } | ||
274 | |||
196 | vin_dbg(vin, "Requested %ux%u Got %ux%u bpl: %d size: %d\n", | 275 | vin_dbg(vin, "Requested %ux%u Got %ux%u bpl: %d size: %d\n", |
197 | rwidth, rheight, pix->width, pix->height, | 276 | rwidth, rheight, pix->width, pix->height, |
198 | pix->bytesperline, pix->sizeimage); | 277 | pix->bytesperline, pix->sizeimage); |
@@ -219,7 +298,7 @@ static int rvin_try_fmt_vid_cap(struct file *file, void *priv, | |||
219 | struct rvin_source_fmt source; | 298 | struct rvin_source_fmt source; |
220 | 299 | ||
221 | return __rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, | 300 | return __rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, |
222 | &source); | 301 | &source); |
223 | } | 302 | } |
224 | 303 | ||
225 | static int rvin_s_fmt_vid_cap(struct file *file, void *priv, | 304 | static int rvin_s_fmt_vid_cap(struct file *file, void *priv, |
@@ -233,7 +312,7 @@ static int rvin_s_fmt_vid_cap(struct file *file, void *priv, | |||
233 | return -EBUSY; | 312 | return -EBUSY; |
234 | 313 | ||
235 | ret = __rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix, | 314 | ret = __rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix, |
236 | &source); | 315 | &source); |
237 | if (ret) | 316 | if (ret) |
238 | return ret; | 317 | return ret; |
239 | 318 | ||
@@ -242,6 +321,8 @@ static int rvin_s_fmt_vid_cap(struct file *file, void *priv, | |||
242 | 321 | ||
243 | vin->format = f->fmt.pix; | 322 | vin->format = f->fmt.pix; |
244 | 323 | ||
324 | rvin_reset_crop_compose(vin); | ||
325 | |||
245 | return 0; | 326 | return 0; |
246 | } | 327 | } |
247 | 328 | ||
@@ -334,8 +415,8 @@ static int rvin_s_selection(struct file *file, void *fh, | |||
334 | vin->crop = s->r = r; | 415 | vin->crop = s->r = r; |
335 | 416 | ||
336 | vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n", | 417 | vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n", |
337 | r.width, r.height, r.left, r.top, | 418 | r.width, r.height, r.left, r.top, |
338 | vin->source.width, vin->source.height); | 419 | vin->source.width, vin->source.height); |
339 | break; | 420 | break; |
340 | case V4L2_SEL_TGT_COMPOSE: | 421 | case V4L2_SEL_TGT_COMPOSE: |
341 | /* Make sure compose rect fits inside output format */ | 422 | /* Make sure compose rect fits inside output format */ |
@@ -359,8 +440,8 @@ static int rvin_s_selection(struct file *file, void *fh, | |||
359 | vin->compose = s->r = r; | 440 | vin->compose = s->r = r; |
360 | 441 | ||
361 | vin_dbg(vin, "Compose %dx%d@%d:%d in %dx%d\n", | 442 | vin_dbg(vin, "Compose %dx%d@%d:%d in %dx%d\n", |
362 | r.width, r.height, r.left, r.top, | 443 | r.width, r.height, r.left, r.top, |
363 | vin->format.width, vin->format.height); | 444 | vin->format.width, vin->format.height); |
364 | break; | 445 | break; |
365 | default: | 446 | default: |
366 | return -EINVAL; | 447 | return -EINVAL; |
@@ -381,7 +462,7 @@ static int rvin_cropcap(struct file *file, void *priv, | |||
381 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 462 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
382 | return -EINVAL; | 463 | return -EINVAL; |
383 | 464 | ||
384 | return v4l2_subdev_call(sd, video, cropcap, crop); | 465 | return v4l2_subdev_call(sd, video, g_pixelaspect, &crop->pixelaspect); |
385 | } | 466 | } |
386 | 467 | ||
387 | static int rvin_enum_input(struct file *file, void *priv, | 468 | static int rvin_enum_input(struct file *file, void *priv, |
@@ -433,35 +514,14 @@ static int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a) | |||
433 | static int rvin_s_std(struct file *file, void *priv, v4l2_std_id a) | 514 | static int rvin_s_std(struct file *file, void *priv, v4l2_std_id a) |
434 | { | 515 | { |
435 | struct rvin_dev *vin = video_drvdata(file); | 516 | struct rvin_dev *vin = video_drvdata(file); |
436 | struct v4l2_subdev *sd = vin_to_source(vin); | 517 | int ret; |
437 | struct v4l2_subdev_format fmt = { | ||
438 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
439 | }; | ||
440 | struct v4l2_mbus_framefmt *mf = &fmt.format; | ||
441 | int ret = v4l2_subdev_call(sd, video, s_std, a); | ||
442 | 518 | ||
519 | ret = v4l2_subdev_call(vin_to_source(vin), video, s_std, a); | ||
443 | if (ret < 0) | 520 | if (ret < 0) |
444 | return ret; | 521 | return ret; |
445 | 522 | ||
446 | /* Changing the standard will change the width/height */ | 523 | /* Changing the standard will change the width/height */ |
447 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | 524 | return rvin_reset_format(vin); |
448 | if (ret) { | ||
449 | vin_err(vin, "Failed to get initial format\n"); | ||
450 | return ret; | ||
451 | } | ||
452 | |||
453 | vin->format.width = mf->width; | ||
454 | vin->format.height = mf->height; | ||
455 | |||
456 | vin->crop.top = vin->crop.left = 0; | ||
457 | vin->crop.width = mf->width; | ||
458 | vin->crop.height = mf->height; | ||
459 | |||
460 | vin->compose.top = vin->compose.left = 0; | ||
461 | vin->compose.width = mf->width; | ||
462 | vin->compose.height = mf->height; | ||
463 | |||
464 | return 0; | ||
465 | } | 525 | } |
466 | 526 | ||
467 | static int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a) | 527 | static int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a) |
@@ -483,14 +543,14 @@ static int rvin_subscribe_event(struct v4l2_fh *fh, | |||
483 | } | 543 | } |
484 | 544 | ||
485 | static int rvin_enum_dv_timings(struct file *file, void *priv_fh, | 545 | static int rvin_enum_dv_timings(struct file *file, void *priv_fh, |
486 | struct v4l2_enum_dv_timings *timings) | 546 | struct v4l2_enum_dv_timings *timings) |
487 | { | 547 | { |
488 | struct rvin_dev *vin = video_drvdata(file); | 548 | struct rvin_dev *vin = video_drvdata(file); |
489 | struct v4l2_subdev *sd = vin_to_source(vin); | 549 | struct v4l2_subdev *sd = vin_to_source(vin); |
490 | int pad, ret; | 550 | int pad, ret; |
491 | 551 | ||
492 | pad = timings->pad; | 552 | pad = timings->pad; |
493 | timings->pad = vin->src_pad_idx; | 553 | timings->pad = vin->sink_pad_idx; |
494 | 554 | ||
495 | ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings); | 555 | ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings); |
496 | 556 | ||
@@ -500,52 +560,51 @@ static int rvin_enum_dv_timings(struct file *file, void *priv_fh, | |||
500 | } | 560 | } |
501 | 561 | ||
502 | static int rvin_s_dv_timings(struct file *file, void *priv_fh, | 562 | static int rvin_s_dv_timings(struct file *file, void *priv_fh, |
503 | struct v4l2_dv_timings *timings) | 563 | struct v4l2_dv_timings *timings) |
504 | { | 564 | { |
505 | struct rvin_dev *vin = video_drvdata(file); | 565 | struct rvin_dev *vin = video_drvdata(file); |
506 | struct v4l2_subdev *sd = vin_to_source(vin); | 566 | struct v4l2_subdev *sd = vin_to_source(vin); |
507 | int err; | 567 | int ret; |
508 | 568 | ||
509 | err = v4l2_subdev_call(sd, | 569 | ret = v4l2_subdev_call(sd, video, s_dv_timings, timings); |
510 | video, s_dv_timings, timings); | 570 | if (ret) |
511 | if (!err) { | 571 | return ret; |
512 | vin->source.width = timings->bt.width; | 572 | |
513 | vin->source.height = timings->bt.height; | 573 | vin->source.width = timings->bt.width; |
514 | vin->format.width = timings->bt.width; | 574 | vin->source.height = timings->bt.height; |
515 | vin->format.height = timings->bt.height; | 575 | vin->format.width = timings->bt.width; |
516 | } | 576 | vin->format.height = timings->bt.height; |
517 | return err; | 577 | |
578 | return 0; | ||
518 | } | 579 | } |
519 | 580 | ||
520 | static int rvin_g_dv_timings(struct file *file, void *priv_fh, | 581 | static int rvin_g_dv_timings(struct file *file, void *priv_fh, |
521 | struct v4l2_dv_timings *timings) | 582 | struct v4l2_dv_timings *timings) |
522 | { | 583 | { |
523 | struct rvin_dev *vin = video_drvdata(file); | 584 | struct rvin_dev *vin = video_drvdata(file); |
524 | struct v4l2_subdev *sd = vin_to_source(vin); | 585 | struct v4l2_subdev *sd = vin_to_source(vin); |
525 | 586 | ||
526 | return v4l2_subdev_call(sd, | 587 | return v4l2_subdev_call(sd, video, g_dv_timings, timings); |
527 | video, g_dv_timings, timings); | ||
528 | } | 588 | } |
529 | 589 | ||
530 | static int rvin_query_dv_timings(struct file *file, void *priv_fh, | 590 | static int rvin_query_dv_timings(struct file *file, void *priv_fh, |
531 | struct v4l2_dv_timings *timings) | 591 | struct v4l2_dv_timings *timings) |
532 | { | 592 | { |
533 | struct rvin_dev *vin = video_drvdata(file); | 593 | struct rvin_dev *vin = video_drvdata(file); |
534 | struct v4l2_subdev *sd = vin_to_source(vin); | 594 | struct v4l2_subdev *sd = vin_to_source(vin); |
535 | 595 | ||
536 | return v4l2_subdev_call(sd, | 596 | return v4l2_subdev_call(sd, video, query_dv_timings, timings); |
537 | video, query_dv_timings, timings); | ||
538 | } | 597 | } |
539 | 598 | ||
540 | static int rvin_dv_timings_cap(struct file *file, void *priv_fh, | 599 | static int rvin_dv_timings_cap(struct file *file, void *priv_fh, |
541 | struct v4l2_dv_timings_cap *cap) | 600 | struct v4l2_dv_timings_cap *cap) |
542 | { | 601 | { |
543 | struct rvin_dev *vin = video_drvdata(file); | 602 | struct rvin_dev *vin = video_drvdata(file); |
544 | struct v4l2_subdev *sd = vin_to_source(vin); | 603 | struct v4l2_subdev *sd = vin_to_source(vin); |
545 | int pad, ret; | 604 | int pad, ret; |
546 | 605 | ||
547 | pad = cap->pad; | 606 | pad = cap->pad; |
548 | cap->pad = vin->src_pad_idx; | 607 | cap->pad = vin->sink_pad_idx; |
549 | 608 | ||
550 | ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap); | 609 | ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap); |
551 | 610 | ||
@@ -554,6 +613,44 @@ static int rvin_dv_timings_cap(struct file *file, void *priv_fh, | |||
554 | return ret; | 613 | return ret; |
555 | } | 614 | } |
556 | 615 | ||
616 | static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) | ||
617 | { | ||
618 | struct rvin_dev *vin = video_drvdata(file); | ||
619 | struct v4l2_subdev *sd = vin_to_source(vin); | ||
620 | int input, ret; | ||
621 | |||
622 | if (edid->pad) | ||
623 | return -EINVAL; | ||
624 | |||
625 | input = edid->pad; | ||
626 | edid->pad = vin->sink_pad_idx; | ||
627 | |||
628 | ret = v4l2_subdev_call(sd, pad, get_edid, edid); | ||
629 | |||
630 | edid->pad = input; | ||
631 | |||
632 | return ret; | ||
633 | } | ||
634 | |||
635 | static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid) | ||
636 | { | ||
637 | struct rvin_dev *vin = video_drvdata(file); | ||
638 | struct v4l2_subdev *sd = vin_to_source(vin); | ||
639 | int input, ret; | ||
640 | |||
641 | if (edid->pad) | ||
642 | return -EINVAL; | ||
643 | |||
644 | input = edid->pad; | ||
645 | edid->pad = vin->sink_pad_idx; | ||
646 | |||
647 | ret = v4l2_subdev_call(sd, pad, set_edid, edid); | ||
648 | |||
649 | edid->pad = input; | ||
650 | |||
651 | return ret; | ||
652 | } | ||
653 | |||
557 | static const struct v4l2_ioctl_ops rvin_ioctl_ops = { | 654 | static const struct v4l2_ioctl_ops rvin_ioctl_ops = { |
558 | .vidioc_querycap = rvin_querycap, | 655 | .vidioc_querycap = rvin_querycap, |
559 | .vidioc_try_fmt_vid_cap = rvin_try_fmt_vid_cap, | 656 | .vidioc_try_fmt_vid_cap = rvin_try_fmt_vid_cap, |
@@ -576,6 +673,9 @@ static const struct v4l2_ioctl_ops rvin_ioctl_ops = { | |||
576 | .vidioc_s_dv_timings = rvin_s_dv_timings, | 673 | .vidioc_s_dv_timings = rvin_s_dv_timings, |
577 | .vidioc_query_dv_timings = rvin_query_dv_timings, | 674 | .vidioc_query_dv_timings = rvin_query_dv_timings, |
578 | 675 | ||
676 | .vidioc_g_edid = rvin_g_edid, | ||
677 | .vidioc_s_edid = rvin_s_edid, | ||
678 | |||
579 | .vidioc_querystd = rvin_querystd, | 679 | .vidioc_querystd = rvin_querystd, |
580 | .vidioc_g_std = rvin_g_std, | 680 | .vidioc_g_std = rvin_g_std, |
581 | .vidioc_s_std = rvin_s_std, | 681 | .vidioc_s_std = rvin_s_std, |
@@ -767,16 +867,9 @@ static void rvin_notify(struct v4l2_subdev *sd, | |||
767 | 867 | ||
768 | int rvin_v4l2_probe(struct rvin_dev *vin) | 868 | int rvin_v4l2_probe(struct rvin_dev *vin) |
769 | { | 869 | { |
770 | struct v4l2_subdev_format fmt = { | ||
771 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
772 | }; | ||
773 | struct v4l2_mbus_framefmt *mf = &fmt.format; | ||
774 | struct video_device *vdev = &vin->vdev; | 870 | struct video_device *vdev = &vin->vdev; |
775 | struct v4l2_subdev *sd = vin_to_source(vin); | 871 | struct v4l2_subdev *sd = vin_to_source(vin); |
776 | #if defined(CONFIG_MEDIA_CONTROLLER) | 872 | int pad_idx, ret; |
777 | int pad_idx; | ||
778 | #endif | ||
779 | int ret; | ||
780 | 873 | ||
781 | v4l2_set_subdev_hostdata(sd, vin); | 874 | v4l2_set_subdev_hostdata(sd, vin); |
782 | 875 | ||
@@ -823,41 +916,23 @@ int rvin_v4l2_probe(struct rvin_dev *vin) | |||
823 | V4L2_CAP_READWRITE; | 916 | V4L2_CAP_READWRITE; |
824 | 917 | ||
825 | vin->src_pad_idx = 0; | 918 | vin->src_pad_idx = 0; |
826 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
827 | for (pad_idx = 0; pad_idx < sd->entity.num_pads; pad_idx++) | 919 | for (pad_idx = 0; pad_idx < sd->entity.num_pads; pad_idx++) |
828 | if (sd->entity.pads[pad_idx].flags | 920 | if (sd->entity.pads[pad_idx].flags == MEDIA_PAD_FL_SOURCE) |
829 | == MEDIA_PAD_FL_SOURCE) | ||
830 | break; | 921 | break; |
831 | if (pad_idx >= sd->entity.num_pads) | 922 | if (pad_idx >= sd->entity.num_pads) |
832 | return -EINVAL; | 923 | return -EINVAL; |
833 | 924 | ||
834 | vin->src_pad_idx = pad_idx; | 925 | vin->src_pad_idx = pad_idx; |
835 | #endif | ||
836 | fmt.pad = vin->src_pad_idx; | ||
837 | 926 | ||
838 | /* Try to improve our guess of a reasonable window format */ | 927 | vin->sink_pad_idx = 0; |
839 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | 928 | for (pad_idx = 0; pad_idx < sd->entity.num_pads; pad_idx++) |
840 | if (ret) { | 929 | if (sd->entity.pads[pad_idx].flags == MEDIA_PAD_FL_SINK) { |
841 | vin_err(vin, "Failed to get initial format\n"); | 930 | vin->sink_pad_idx = pad_idx; |
842 | return ret; | 931 | break; |
843 | } | 932 | } |
844 | 933 | ||
845 | /* Set default format */ | ||
846 | vin->format.width = mf->width; | ||
847 | vin->format.height = mf->height; | ||
848 | vin->format.colorspace = mf->colorspace; | ||
849 | vin->format.field = mf->field; | ||
850 | vin->format.pixelformat = RVIN_DEFAULT_FORMAT; | 934 | vin->format.pixelformat = RVIN_DEFAULT_FORMAT; |
851 | 935 | rvin_reset_format(vin); | |
852 | |||
853 | /* Set initial crop and compose */ | ||
854 | vin->crop.top = vin->crop.left = 0; | ||
855 | vin->crop.width = mf->width; | ||
856 | vin->crop.height = mf->height; | ||
857 | |||
858 | vin->compose.top = vin->compose.left = 0; | ||
859 | vin->compose.width = mf->width; | ||
860 | vin->compose.height = mf->height; | ||
861 | 936 | ||
862 | ret = video_register_device(&vin->vdev, VFL_TYPE_GRABBER, -1); | 937 | ret = video_register_device(&vin->vdev, VFL_TYPE_GRABBER, -1); |
863 | if (ret) { | 938 | if (ret) { |
diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 31ad39a39937..727e215c0871 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h | |||
@@ -30,9 +30,9 @@ | |||
30 | #define HW_BUFFER_MASK 0x7f | 30 | #define HW_BUFFER_MASK 0x7f |
31 | 31 | ||
32 | enum chip_id { | 32 | enum chip_id { |
33 | RCAR_GEN2, | ||
34 | RCAR_H1, | 33 | RCAR_H1, |
35 | RCAR_M1, | 34 | RCAR_M1, |
35 | RCAR_GEN2, | ||
36 | }; | 36 | }; |
37 | 37 | ||
38 | /** | 38 | /** |
@@ -50,12 +50,10 @@ enum rvin_dma_state { | |||
50 | 50 | ||
51 | /** | 51 | /** |
52 | * struct rvin_source_fmt - Source information | 52 | * struct rvin_source_fmt - Source information |
53 | * @code: Media bus format from source | ||
54 | * @width: Width from source | 53 | * @width: Width from source |
55 | * @height: Height from source | 54 | * @height: Height from source |
56 | */ | 55 | */ |
57 | struct rvin_source_fmt { | 56 | struct rvin_source_fmt { |
58 | u32 code; | ||
59 | u32 width; | 57 | u32 width; |
60 | u32 height; | 58 | u32 height; |
61 | }; | 59 | }; |
@@ -70,12 +68,19 @@ struct rvin_video_format { | |||
70 | u8 bpp; | 68 | u8 bpp; |
71 | }; | 69 | }; |
72 | 70 | ||
71 | /** | ||
72 | * struct rvin_graph_entity - Video endpoint from async framework | ||
73 | * @asd: sub-device descriptor for async framework | ||
74 | * @subdev: subdevice matched using async framework | ||
75 | * @code: Media bus format from source | ||
76 | * @mbus_cfg: Media bus format from DT | ||
77 | */ | ||
73 | struct rvin_graph_entity { | 78 | struct rvin_graph_entity { |
74 | struct device_node *node; | ||
75 | struct media_entity *entity; | ||
76 | |||
77 | struct v4l2_async_subdev asd; | 79 | struct v4l2_async_subdev asd; |
78 | struct v4l2_subdev *subdev; | 80 | struct v4l2_subdev *subdev; |
81 | |||
82 | u32 code; | ||
83 | struct v4l2_mbus_config mbus_cfg; | ||
79 | }; | 84 | }; |
80 | 85 | ||
81 | /** | 86 | /** |
@@ -83,14 +88,14 @@ struct rvin_graph_entity { | |||
83 | * @dev: (OF) device | 88 | * @dev: (OF) device |
84 | * @base: device I/O register space remapped to virtual memory | 89 | * @base: device I/O register space remapped to virtual memory |
85 | * @chip: type of VIN chip | 90 | * @chip: type of VIN chip |
86 | * @mbus_cfg media bus configuration | ||
87 | * | 91 | * |
88 | * @vdev: V4L2 video device associated with VIN | 92 | * @vdev: V4L2 video device associated with VIN |
89 | * @v4l2_dev: V4L2 device | 93 | * @v4l2_dev: V4L2 device |
90 | * @src_pad_idx: source pad index for media controller drivers | 94 | * @src_pad_idx: source pad index for media controller drivers |
95 | * @sink_pad_idx: sink pad index for media controller drivers | ||
91 | * @ctrl_handler: V4L2 control handler | 96 | * @ctrl_handler: V4L2 control handler |
92 | * @notifier: V4L2 asynchronous subdevs notifier | 97 | * @notifier: V4L2 asynchronous subdevs notifier |
93 | * @entity: entity in the DT for subdevice | 98 | * @digital: entity in the DT for local digital subdevice |
94 | * | 99 | * |
95 | * @lock: protects @queue | 100 | * @lock: protects @queue |
96 | * @queue: vb2 buffers queue | 101 | * @queue: vb2 buffers queue |
@@ -113,14 +118,14 @@ struct rvin_dev { | |||
113 | struct device *dev; | 118 | struct device *dev; |
114 | void __iomem *base; | 119 | void __iomem *base; |
115 | enum chip_id chip; | 120 | enum chip_id chip; |
116 | struct v4l2_mbus_config mbus_cfg; | ||
117 | 121 | ||
118 | struct video_device vdev; | 122 | struct video_device vdev; |
119 | struct v4l2_device v4l2_dev; | 123 | struct v4l2_device v4l2_dev; |
120 | int src_pad_idx; | 124 | int src_pad_idx; |
125 | int sink_pad_idx; | ||
121 | struct v4l2_ctrl_handler ctrl_handler; | 126 | struct v4l2_ctrl_handler ctrl_handler; |
122 | struct v4l2_async_notifier notifier; | 127 | struct v4l2_async_notifier notifier; |
123 | struct rvin_graph_entity entity; | 128 | struct rvin_graph_entity digital; |
124 | 129 | ||
125 | struct mutex lock; | 130 | struct mutex lock; |
126 | struct vb2_queue queue; | 131 | struct vb2_queue queue; |
@@ -139,7 +144,7 @@ struct rvin_dev { | |||
139 | struct v4l2_rect compose; | 144 | struct v4l2_rect compose; |
140 | }; | 145 | }; |
141 | 146 | ||
142 | #define vin_to_source(vin) vin->entity.subdev | 147 | #define vin_to_source(vin) vin->digital.subdev |
143 | 148 | ||
144 | /* Debug */ | 149 | /* Debug */ |
145 | #define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg) | 150 | #define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg) |
diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c index 16782ceb29c3..d1746ecc645d 100644 --- a/drivers/media/platform/rcar_jpu.c +++ b/drivers/media/platform/rcar_jpu.c | |||
@@ -1183,7 +1183,7 @@ static void jpu_stop_streaming(struct vb2_queue *vq) | |||
1183 | } | 1183 | } |
1184 | } | 1184 | } |
1185 | 1185 | ||
1186 | static struct vb2_ops jpu_qops = { | 1186 | static const struct vb2_ops jpu_qops = { |
1187 | .queue_setup = jpu_queue_setup, | 1187 | .queue_setup = jpu_queue_setup, |
1188 | .buf_prepare = jpu_buf_prepare, | 1188 | .buf_prepare = jpu_buf_prepare, |
1189 | .buf_queue = jpu_buf_queue, | 1189 | .buf_queue = jpu_buf_queue, |
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 391dd7a7b362..62c0dec30b59 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c | |||
@@ -138,7 +138,7 @@ static void g2d_buf_queue(struct vb2_buffer *vb) | |||
138 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); | 138 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); |
139 | } | 139 | } |
140 | 140 | ||
141 | static struct vb2_ops g2d_qops = { | 141 | static const struct vb2_ops g2d_qops = { |
142 | .queue_setup = g2d_queue_setup, | 142 | .queue_setup = g2d_queue_setup, |
143 | .buf_prepare = g2d_buf_prepare, | 143 | .buf_prepare = g2d_buf_prepare, |
144 | .buf_queue = g2d_buf_queue, | 144 | .buf_queue = g2d_buf_queue, |
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 785e6936c881..52dc7941db65 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c | |||
@@ -537,6 +537,7 @@ static const u32 fourcc_to_dwngrd_schema_id[] = { | |||
537 | static int s5p_jpeg_get_dwngrd_sch_id_by_fourcc(u32 fourcc) | 537 | static int s5p_jpeg_get_dwngrd_sch_id_by_fourcc(u32 fourcc) |
538 | { | 538 | { |
539 | int i; | 539 | int i; |
540 | |||
540 | for (i = 0; i < ARRAY_SIZE(fourcc_to_dwngrd_schema_id); ++i) { | 541 | for (i = 0; i < ARRAY_SIZE(fourcc_to_dwngrd_schema_id); ++i) { |
541 | if (fourcc_to_dwngrd_schema_id[i] == fourcc) | 542 | if (fourcc_to_dwngrd_schema_id[i] == fourcc) |
542 | return i; | 543 | return i; |
@@ -1246,17 +1247,18 @@ static int s5p_jpeg_querycap(struct file *file, void *priv, | |||
1246 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); | 1247 | struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); |
1247 | 1248 | ||
1248 | if (ctx->mode == S5P_JPEG_ENCODE) { | 1249 | if (ctx->mode == S5P_JPEG_ENCODE) { |
1249 | strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder", | 1250 | strlcpy(cap->driver, S5P_JPEG_M2M_NAME, |
1250 | sizeof(cap->driver)); | 1251 | sizeof(cap->driver)); |
1251 | strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder", | 1252 | strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder", |
1252 | sizeof(cap->card)); | 1253 | sizeof(cap->card)); |
1253 | } else { | 1254 | } else { |
1254 | strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder", | 1255 | strlcpy(cap->driver, S5P_JPEG_M2M_NAME, |
1255 | sizeof(cap->driver)); | 1256 | sizeof(cap->driver)); |
1256 | strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder", | 1257 | strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder", |
1257 | sizeof(cap->card)); | 1258 | sizeof(cap->card)); |
1258 | } | 1259 | } |
1259 | cap->bus_info[0] = 0; | 1260 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", |
1261 | dev_name(ctx->jpeg->dev)); | ||
1260 | cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; | 1262 | cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; |
1261 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | 1263 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; |
1262 | return 0; | 1264 | return 0; |
@@ -1273,7 +1275,8 @@ static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n, | |||
1273 | if (num == f->index) | 1275 | if (num == f->index) |
1274 | break; | 1276 | break; |
1275 | /* Correct type but haven't reached our index yet, | 1277 | /* Correct type but haven't reached our index yet, |
1276 | * just increment per-type index */ | 1278 | * just increment per-type index |
1279 | */ | ||
1277 | ++num; | 1280 | ++num; |
1278 | } | 1281 | } |
1279 | } | 1282 | } |
@@ -1349,6 +1352,7 @@ static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f) | |||
1349 | pix->bytesperline = 0; | 1352 | pix->bytesperline = 0; |
1350 | if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) { | 1353 | if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) { |
1351 | u32 bpl = q_data->w; | 1354 | u32 bpl = q_data->w; |
1355 | |||
1352 | if (q_data->fmt->colplanes == 1) | 1356 | if (q_data->fmt->colplanes == 1) |
1353 | bpl = (bpl * q_data->fmt->depth) >> 3; | 1357 | bpl = (bpl * q_data->fmt->depth) >> 3; |
1354 | pix->bytesperline = bpl; | 1358 | pix->bytesperline = bpl; |
@@ -1374,6 +1378,7 @@ static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx, | |||
1374 | 1378 | ||
1375 | for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) { | 1379 | for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) { |
1376 | struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k]; | 1380 | struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k]; |
1381 | |||
1377 | if (fmt->fourcc == pixelformat && | 1382 | if (fmt->fourcc == pixelformat && |
1378 | fmt->flags & fmt_flag && | 1383 | fmt->flags & fmt_flag && |
1379 | fmt->flags & ctx->jpeg->variant->fmt_ver_flag) { | 1384 | fmt->flags & ctx->jpeg->variant->fmt_ver_flag) { |
@@ -1431,7 +1436,8 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt, | |||
1431 | return -EINVAL; | 1436 | return -EINVAL; |
1432 | 1437 | ||
1433 | /* V4L2 specification suggests the driver corrects the format struct | 1438 | /* V4L2 specification suggests the driver corrects the format struct |
1434 | * if any of the dimensions is unsupported */ | 1439 | * if any of the dimensions is unsupported |
1440 | */ | ||
1435 | if (q_type == FMT_TYPE_OUTPUT) | 1441 | if (q_type == FMT_TYPE_OUTPUT) |
1436 | jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH, | 1442 | jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH, |
1437 | S5P_JPEG_MAX_WIDTH, 0, | 1443 | S5P_JPEG_MAX_WIDTH, 0, |
@@ -2489,6 +2495,7 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb) | |||
2489 | if (ctx->mode == S5P_JPEG_DECODE && | 2495 | if (ctx->mode == S5P_JPEG_DECODE && |
2490 | vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | 2496 | vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { |
2491 | struct s5p_jpeg_q_data tmp, *q_data; | 2497 | struct s5p_jpeg_q_data tmp, *q_data; |
2498 | |||
2492 | ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp, | 2499 | ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp, |
2493 | (unsigned long)vb2_plane_vaddr(vb, 0), | 2500 | (unsigned long)vb2_plane_vaddr(vb, 0), |
2494 | min((unsigned long)ctx->out_q.size, | 2501 | min((unsigned long)ctx->out_q.size, |
@@ -2538,7 +2545,7 @@ static void s5p_jpeg_stop_streaming(struct vb2_queue *q) | |||
2538 | pm_runtime_put(ctx->jpeg->dev); | 2545 | pm_runtime_put(ctx->jpeg->dev); |
2539 | } | 2546 | } |
2540 | 2547 | ||
2541 | static struct vb2_ops s5p_jpeg_qops = { | 2548 | static const struct vb2_ops s5p_jpeg_qops = { |
2542 | .queue_setup = s5p_jpeg_queue_setup, | 2549 | .queue_setup = s5p_jpeg_queue_setup, |
2543 | .buf_prepare = s5p_jpeg_buf_prepare, | 2550 | .buf_prepare = s5p_jpeg_buf_prepare, |
2544 | .buf_queue = s5p_jpeg_buf_queue, | 2551 | .buf_queue = s5p_jpeg_buf_queue, |
@@ -2996,27 +3003,11 @@ static int s5p_jpeg_runtime_resume(struct device *dev) | |||
2996 | } | 3003 | } |
2997 | #endif /* CONFIG_PM */ | 3004 | #endif /* CONFIG_PM */ |
2998 | 3005 | ||
2999 | #ifdef CONFIG_PM_SLEEP | ||
3000 | static int s5p_jpeg_suspend(struct device *dev) | ||
3001 | { | ||
3002 | if (pm_runtime_suspended(dev)) | ||
3003 | return 0; | ||
3004 | |||
3005 | return s5p_jpeg_runtime_suspend(dev); | ||
3006 | } | ||
3007 | |||
3008 | static int s5p_jpeg_resume(struct device *dev) | ||
3009 | { | ||
3010 | if (pm_runtime_suspended(dev)) | ||
3011 | return 0; | ||
3012 | |||
3013 | return s5p_jpeg_runtime_resume(dev); | ||
3014 | } | ||
3015 | #endif | ||
3016 | |||
3017 | static const struct dev_pm_ops s5p_jpeg_pm_ops = { | 3006 | static const struct dev_pm_ops s5p_jpeg_pm_ops = { |
3018 | SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume) | 3007 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
3019 | SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL) | 3008 | pm_runtime_force_resume) |
3009 | SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, | ||
3010 | NULL) | ||
3020 | }; | 3011 | }; |
3021 | 3012 | ||
3022 | static struct s5p_jpeg_variant s5p_jpeg_drvdata = { | 3013 | static struct s5p_jpeg_variant s5p_jpeg_drvdata = { |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index e3f104fafd0a..0a5b8f5e011e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c | |||
@@ -153,7 +153,7 @@ static void s5p_mfc_watchdog(unsigned long arg) | |||
153 | * error. Now it is time to kill all instances and | 153 | * error. Now it is time to kill all instances and |
154 | * reset the MFC. */ | 154 | * reset the MFC. */ |
155 | mfc_err("Time out during waiting for HW\n"); | 155 | mfc_err("Time out during waiting for HW\n"); |
156 | queue_work(dev->watchdog_workqueue, &dev->watchdog_work); | 156 | schedule_work(&dev->watchdog_work); |
157 | } | 157 | } |
158 | dev->watchdog_timer.expires = jiffies + | 158 | dev->watchdog_timer.expires = jiffies + |
159 | msecs_to_jiffies(MFC_WATCHDOG_INTERVAL); | 159 | msecs_to_jiffies(MFC_WATCHDOG_INTERVAL); |
@@ -494,7 +494,6 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, | |||
494 | s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); | 494 | s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); |
495 | s5p_mfc_clock_off(); | 495 | s5p_mfc_clock_off(); |
496 | wake_up_dev(dev, reason, err); | 496 | wake_up_dev(dev, reason, err); |
497 | return; | ||
498 | } | 497 | } |
499 | 498 | ||
500 | /* Header parsing interrupt handling */ | 499 | /* Header parsing interrupt handling */ |
@@ -759,7 +758,6 @@ static int s5p_mfc_open(struct file *file) | |||
759 | /* Allocate memory for context */ | 758 | /* Allocate memory for context */ |
760 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | 759 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
761 | if (!ctx) { | 760 | if (!ctx) { |
762 | mfc_err("Not enough memory\n"); | ||
763 | ret = -ENOMEM; | 761 | ret = -ENOMEM; |
764 | goto err_alloc; | 762 | goto err_alloc; |
765 | } | 763 | } |
@@ -776,7 +774,7 @@ static int s5p_mfc_open(struct file *file) | |||
776 | while (dev->ctx[ctx->num]) { | 774 | while (dev->ctx[ctx->num]) { |
777 | ctx->num++; | 775 | ctx->num++; |
778 | if (ctx->num >= MFC_NUM_CONTEXTS) { | 776 | if (ctx->num >= MFC_NUM_CONTEXTS) { |
779 | mfc_err("Too many open contexts\n"); | 777 | mfc_debug(2, "Too many open contexts\n"); |
780 | ret = -EBUSY; | 778 | ret = -EBUSY; |
781 | goto err_no_ctx; | 779 | goto err_no_ctx; |
782 | } | 780 | } |
@@ -924,39 +922,50 @@ static int s5p_mfc_release(struct file *file) | |||
924 | struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); | 922 | struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); |
925 | struct s5p_mfc_dev *dev = ctx->dev; | 923 | struct s5p_mfc_dev *dev = ctx->dev; |
926 | 924 | ||
925 | /* if dev is null, do cleanup that doesn't need dev */ | ||
927 | mfc_debug_enter(); | 926 | mfc_debug_enter(); |
928 | mutex_lock(&dev->mfc_mutex); | 927 | if (dev) |
928 | mutex_lock(&dev->mfc_mutex); | ||
929 | s5p_mfc_clock_on(); | 929 | s5p_mfc_clock_on(); |
930 | vb2_queue_release(&ctx->vq_src); | 930 | vb2_queue_release(&ctx->vq_src); |
931 | vb2_queue_release(&ctx->vq_dst); | 931 | vb2_queue_release(&ctx->vq_dst); |
932 | /* Mark context as idle */ | 932 | if (dev) { |
933 | clear_work_bit_irqsave(ctx); | 933 | /* Mark context as idle */ |
934 | /* If instance was initialised and not yet freed, | 934 | clear_work_bit_irqsave(ctx); |
935 | * return instance and free resources */ | 935 | /* |
936 | if (ctx->state != MFCINST_FREE && ctx->state != MFCINST_INIT) { | 936 | * If instance was initialised and not yet freed, |
937 | mfc_debug(2, "Has to free instance\n"); | 937 | * return instance and free resources |
938 | s5p_mfc_close_mfc_inst(dev, ctx); | 938 | */ |
939 | } | 939 | if (ctx->state != MFCINST_FREE && ctx->state != MFCINST_INIT) { |
940 | /* hardware locking scheme */ | 940 | mfc_debug(2, "Has to free instance\n"); |
941 | if (dev->curr_ctx == ctx->num) | 941 | s5p_mfc_close_mfc_inst(dev, ctx); |
942 | clear_bit(0, &dev->hw_lock); | 942 | } |
943 | dev->num_inst--; | 943 | /* hardware locking scheme */ |
944 | if (dev->num_inst == 0) { | 944 | if (dev->curr_ctx == ctx->num) |
945 | mfc_debug(2, "Last instance\n"); | 945 | clear_bit(0, &dev->hw_lock); |
946 | s5p_mfc_deinit_hw(dev); | 946 | dev->num_inst--; |
947 | del_timer_sync(&dev->watchdog_timer); | 947 | if (dev->num_inst == 0) { |
948 | if (s5p_mfc_power_off() < 0) | 948 | mfc_debug(2, "Last instance\n"); |
949 | mfc_err("Power off failed\n"); | 949 | s5p_mfc_deinit_hw(dev); |
950 | del_timer_sync(&dev->watchdog_timer); | ||
951 | if (s5p_mfc_power_off() < 0) | ||
952 | mfc_err("Power off failed\n"); | ||
953 | } | ||
950 | } | 954 | } |
951 | mfc_debug(2, "Shutting down clock\n"); | 955 | mfc_debug(2, "Shutting down clock\n"); |
952 | s5p_mfc_clock_off(); | 956 | s5p_mfc_clock_off(); |
953 | dev->ctx[ctx->num] = NULL; | 957 | if (dev) |
958 | dev->ctx[ctx->num] = NULL; | ||
954 | s5p_mfc_dec_ctrls_delete(ctx); | 959 | s5p_mfc_dec_ctrls_delete(ctx); |
955 | v4l2_fh_del(&ctx->fh); | 960 | v4l2_fh_del(&ctx->fh); |
956 | v4l2_fh_exit(&ctx->fh); | 961 | /* vdev is gone if dev is null */ |
962 | if (dev) | ||
963 | v4l2_fh_exit(&ctx->fh); | ||
957 | kfree(ctx); | 964 | kfree(ctx); |
958 | mfc_debug_leave(); | 965 | mfc_debug_leave(); |
959 | mutex_unlock(&dev->mfc_mutex); | 966 | if (dev) |
967 | mutex_unlock(&dev->mfc_mutex); | ||
968 | |||
960 | return 0; | 969 | return 0; |
961 | } | 970 | } |
962 | 971 | ||
@@ -1158,10 +1167,6 @@ static int s5p_mfc_probe(struct platform_device *pdev) | |||
1158 | dev->variant = mfc_get_drv_data(pdev); | 1167 | dev->variant = mfc_get_drv_data(pdev); |
1159 | 1168 | ||
1160 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1169 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1161 | if (res == NULL) { | ||
1162 | dev_err(&pdev->dev, "failed to get io resource\n"); | ||
1163 | return -ENOENT; | ||
1164 | } | ||
1165 | dev->regs_base = devm_ioremap_resource(&pdev->dev, res); | 1170 | dev->regs_base = devm_ioremap_resource(&pdev->dev, res); |
1166 | if (IS_ERR(dev->regs_base)) | 1171 | if (IS_ERR(dev->regs_base)) |
1167 | return PTR_ERR(dev->regs_base); | 1172 | return PTR_ERR(dev->regs_base); |
@@ -1241,7 +1246,6 @@ static int s5p_mfc_probe(struct platform_device *pdev) | |||
1241 | platform_set_drvdata(pdev, dev); | 1246 | platform_set_drvdata(pdev, dev); |
1242 | 1247 | ||
1243 | dev->hw_lock = 0; | 1248 | dev->hw_lock = 0; |
1244 | dev->watchdog_workqueue = create_singlethread_workqueue(S5P_MFC_NAME); | ||
1245 | INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker); | 1249 | INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker); |
1246 | atomic_set(&dev->watchdog_cnt, 0); | 1250 | atomic_set(&dev->watchdog_cnt, 0); |
1247 | init_timer(&dev->watchdog_timer); | 1251 | init_timer(&dev->watchdog_timer); |
@@ -1298,12 +1302,28 @@ err_dma: | |||
1298 | static int s5p_mfc_remove(struct platform_device *pdev) | 1302 | static int s5p_mfc_remove(struct platform_device *pdev) |
1299 | { | 1303 | { |
1300 | struct s5p_mfc_dev *dev = platform_get_drvdata(pdev); | 1304 | struct s5p_mfc_dev *dev = platform_get_drvdata(pdev); |
1305 | struct s5p_mfc_ctx *ctx; | ||
1306 | int i; | ||
1301 | 1307 | ||
1302 | v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name); | 1308 | v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name); |
1303 | 1309 | ||
1310 | /* | ||
1311 | * Clear ctx dev pointer to avoid races between s5p_mfc_remove() | ||
1312 | * and s5p_mfc_release() and s5p_mfc_release() accessing ctx->dev | ||
1313 | * after s5p_mfc_remove() is run during unbind. | ||
1314 | */ | ||
1315 | mutex_lock(&dev->mfc_mutex); | ||
1316 | for (i = 0; i < MFC_NUM_CONTEXTS; i++) { | ||
1317 | ctx = dev->ctx[i]; | ||
1318 | if (!ctx) | ||
1319 | continue; | ||
1320 | /* clear ctx->dev */ | ||
1321 | ctx->dev = NULL; | ||
1322 | } | ||
1323 | mutex_unlock(&dev->mfc_mutex); | ||
1324 | |||
1304 | del_timer_sync(&dev->watchdog_timer); | 1325 | del_timer_sync(&dev->watchdog_timer); |
1305 | flush_workqueue(dev->watchdog_workqueue); | 1326 | flush_work(&dev->watchdog_work); |
1306 | destroy_workqueue(dev->watchdog_workqueue); | ||
1307 | 1327 | ||
1308 | video_unregister_device(dev->vfd_enc); | 1328 | video_unregister_device(dev->vfd_enc); |
1309 | video_unregister_device(dev->vfd_dec); | 1329 | video_unregister_device(dev->vfd_dec); |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 373e346fce3e..46b99f28cbd7 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h | |||
@@ -292,7 +292,9 @@ struct s5p_mfc_priv_buf { | |||
292 | * @warn_start: hardware error code from which warnings start | 292 | * @warn_start: hardware error code from which warnings start |
293 | * @mfc_ops: ops structure holding HW operation function pointers | 293 | * @mfc_ops: ops structure holding HW operation function pointers |
294 | * @mfc_cmds: cmd structure holding HW commands function pointers | 294 | * @mfc_cmds: cmd structure holding HW commands function pointers |
295 | * @mfc_regs: structure holding MFC registers | ||
295 | * @fw_ver: loaded firmware sub-version | 296 | * @fw_ver: loaded firmware sub-version |
297 | * risc_on: flag indicates RISC is on or off | ||
296 | * | 298 | * |
297 | */ | 299 | */ |
298 | struct s5p_mfc_dev { | 300 | struct s5p_mfc_dev { |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 47c997d9e8cb..52081ddc9bf2 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | |||
@@ -776,11 +776,12 @@ static int vidioc_g_crop(struct file *file, void *priv, | |||
776 | u32 left, right, top, bottom; | 776 | u32 left, right, top, bottom; |
777 | 777 | ||
778 | if (ctx->state != MFCINST_HEAD_PARSED && | 778 | if (ctx->state != MFCINST_HEAD_PARSED && |
779 | ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING | 779 | ctx->state != MFCINST_RUNNING && |
780 | && ctx->state != MFCINST_FINISHED) { | 780 | ctx->state != MFCINST_FINISHING && |
781 | mfc_err("Cannont set crop\n"); | 781 | ctx->state != MFCINST_FINISHED) { |
782 | return -EINVAL; | 782 | mfc_err("Can not get crop information\n"); |
783 | } | 783 | return -EINVAL; |
784 | } | ||
784 | if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) { | 785 | if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) { |
785 | left = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_h, ctx); | 786 | left = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_h, ctx); |
786 | right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT; | 787 | right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT; |
diff --git a/drivers/media/platform/s5p-tv/Kconfig b/drivers/media/platform/s5p-tv/Kconfig deleted file mode 100644 index 697aaed42486..000000000000 --- a/drivers/media/platform/s5p-tv/Kconfig +++ /dev/null | |||
@@ -1,88 +0,0 @@ | |||
1 | # drivers/media/platform/s5p-tv/Kconfig | ||
2 | # | ||
3 | # Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
4 | # http://www.samsung.com/ | ||
5 | # Tomasz Stanislawski <t.stanislaws@samsung.com> | ||
6 | # | ||
7 | # Licensed under GPL | ||
8 | |||
9 | config VIDEO_SAMSUNG_S5P_TV | ||
10 | bool "Samsung TV driver for S5P platform" | ||
11 | depends on PM | ||
12 | depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST | ||
13 | default n | ||
14 | ---help--- | ||
15 | Say Y here to enable selecting the TV output devices for | ||
16 | Samsung S5P platform. | ||
17 | |||
18 | if VIDEO_SAMSUNG_S5P_TV | ||
19 | |||
20 | config VIDEO_SAMSUNG_S5P_HDMI | ||
21 | tristate "Samsung HDMI Driver" | ||
22 | depends on VIDEO_V4L2 | ||
23 | depends on I2C | ||
24 | depends on VIDEO_SAMSUNG_S5P_TV | ||
25 | select VIDEO_SAMSUNG_S5P_HDMIPHY | ||
26 | help | ||
27 | Say Y here if you want support for the HDMI output | ||
28 | interface in S5P Samsung SoC. The driver can be compiled | ||
29 | as module. It is an auxiliary driver, that exposes a V4L2 | ||
30 | subdev for use by other drivers. This driver requires | ||
31 | hdmiphy driver to work correctly. | ||
32 | |||
33 | config VIDEO_SAMSUNG_S5P_HDMI_DEBUG | ||
34 | bool "Enable debug for HDMI Driver" | ||
35 | depends on VIDEO_SAMSUNG_S5P_HDMI | ||
36 | default n | ||
37 | help | ||
38 | Enables debugging for HDMI driver. | ||
39 | |||
40 | config VIDEO_SAMSUNG_S5P_HDMIPHY | ||
41 | tristate "Samsung HDMIPHY Driver" | ||
42 | depends on VIDEO_DEV && VIDEO_V4L2 && I2C | ||
43 | depends on VIDEO_SAMSUNG_S5P_TV | ||
44 | help | ||
45 | Say Y here if you want support for the physical HDMI | ||
46 | interface in S5P Samsung SoC. The driver can be compiled | ||
47 | as module. It is an I2C driver, that exposes a V4L2 | ||
48 | subdev for use by other drivers. | ||
49 | |||
50 | config VIDEO_SAMSUNG_S5P_SII9234 | ||
51 | tristate "Samsung SII9234 Driver" | ||
52 | depends on VIDEO_DEV && VIDEO_V4L2 && I2C | ||
53 | depends on VIDEO_SAMSUNG_S5P_TV | ||
54 | help | ||
55 | Say Y here if you want support for the MHL interface | ||
56 | in S5P Samsung SoC. The driver can be compiled | ||
57 | as module. It is an I2C driver, that exposes a V4L2 | ||
58 | subdev for use by other drivers. | ||
59 | |||
60 | config VIDEO_SAMSUNG_S5P_SDO | ||
61 | tristate "Samsung Analog TV Driver" | ||
62 | depends on VIDEO_DEV && VIDEO_V4L2 | ||
63 | depends on VIDEO_SAMSUNG_S5P_TV | ||
64 | help | ||
65 | Say Y here if you want support for the analog TV output | ||
66 | interface in S5P Samsung SoC. The driver can be compiled | ||
67 | as module. It is an auxiliary driver, that exposes a V4L2 | ||
68 | subdev for use by other drivers. This driver requires | ||
69 | hdmiphy driver to work correctly. | ||
70 | |||
71 | config VIDEO_SAMSUNG_S5P_MIXER | ||
72 | tristate "Samsung Mixer and Video Processor Driver" | ||
73 | depends on VIDEO_DEV && VIDEO_V4L2 | ||
74 | depends on VIDEO_SAMSUNG_S5P_TV | ||
75 | depends on HAS_DMA | ||
76 | select VIDEOBUF2_DMA_CONTIG | ||
77 | help | ||
78 | Say Y here if you want support for the Mixer in Samsung S5P SoCs. | ||
79 | This device produce image data to one of output interfaces. | ||
80 | |||
81 | config VIDEO_SAMSUNG_S5P_MIXER_DEBUG | ||
82 | bool "Enable debug for Mixer Driver" | ||
83 | depends on VIDEO_SAMSUNG_S5P_MIXER | ||
84 | default n | ||
85 | help | ||
86 | Enables debugging for Mixer driver. | ||
87 | |||
88 | endif # VIDEO_SAMSUNG_S5P_TV | ||
diff --git a/drivers/media/platform/s5p-tv/Makefile b/drivers/media/platform/s5p-tv/Makefile deleted file mode 100644 index 7cd47902e269..000000000000 --- a/drivers/media/platform/s5p-tv/Makefile +++ /dev/null | |||
@@ -1,19 +0,0 @@ | |||
1 | # drivers/media/platform/samsung/tvout/Makefile | ||
2 | # | ||
3 | # Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
4 | # http://www.samsung.com/ | ||
5 | # Tomasz Stanislawski <t.stanislaws@samsung.com> | ||
6 | # | ||
7 | # Licensed under GPL | ||
8 | |||
9 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o | ||
10 | s5p-hdmiphy-y += hdmiphy_drv.o | ||
11 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SII9234) += s5p-sii9234.o | ||
12 | s5p-sii9234-y += sii9234_drv.o | ||
13 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o | ||
14 | s5p-hdmi-y += hdmi_drv.o | ||
15 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o | ||
16 | s5p-sdo-y += sdo_drv.o | ||
17 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MIXER) += s5p-mixer.o | ||
18 | s5p-mixer-y += mixer_drv.o mixer_video.o mixer_reg.o mixer_grp_layer.o mixer_vp_layer.o | ||
19 | |||
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c deleted file mode 100644 index e71b13e40f59..000000000000 --- a/drivers/media/platform/s5p-tv/hdmi_drv.c +++ /dev/null | |||
@@ -1,1059 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung HDMI interface driver | ||
3 | * | ||
4 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
5 | * | ||
6 | * Tomasz Stanislawski, <t.stanislaws@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 as published | ||
10 | * by the Free Software Foundiation. either version 2 of the License, | ||
11 | * or (at your option) any later version | ||
12 | */ | ||
13 | |||
14 | #define pr_fmt(fmt) "s5p-tv (hdmi_drv): " fmt | ||
15 | |||
16 | #ifdef CONFIG_VIDEO_SAMSUNG_S5P_HDMI_DEBUG | ||
17 | #define DEBUG | ||
18 | #endif | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <media/v4l2-subdev.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/bug.h> | ||
31 | #include <linux/pm_runtime.h> | ||
32 | #include <linux/clk.h> | ||
33 | #include <linux/regulator/consumer.h> | ||
34 | #include <linux/v4l2-dv-timings.h> | ||
35 | |||
36 | #include <linux/platform_data/media/s5p_hdmi.h> | ||
37 | #include <media/v4l2-common.h> | ||
38 | #include <media/v4l2-dev.h> | ||
39 | #include <media/v4l2-device.h> | ||
40 | #include <media/v4l2-dv-timings.h> | ||
41 | |||
42 | #include "regs-hdmi.h" | ||
43 | |||
44 | MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>"); | ||
45 | MODULE_DESCRIPTION("Samsung HDMI"); | ||
46 | MODULE_LICENSE("GPL"); | ||
47 | |||
48 | struct hdmi_pulse { | ||
49 | u32 beg; | ||
50 | u32 end; | ||
51 | }; | ||
52 | |||
53 | struct hdmi_timings { | ||
54 | struct hdmi_pulse hact; | ||
55 | u32 hsyn_pol; /* 0 - high, 1 - low */ | ||
56 | struct hdmi_pulse hsyn; | ||
57 | u32 interlaced; | ||
58 | struct hdmi_pulse vact[2]; | ||
59 | u32 vsyn_pol; /* 0 - high, 1 - low */ | ||
60 | u32 vsyn_off; | ||
61 | struct hdmi_pulse vsyn[2]; | ||
62 | }; | ||
63 | |||
64 | struct hdmi_resources { | ||
65 | struct clk *hdmi; | ||
66 | struct clk *sclk_hdmi; | ||
67 | struct clk *sclk_pixel; | ||
68 | struct clk *sclk_hdmiphy; | ||
69 | struct clk *hdmiphy; | ||
70 | struct regulator_bulk_data *regul_bulk; | ||
71 | int regul_count; | ||
72 | }; | ||
73 | |||
74 | struct hdmi_device { | ||
75 | /** base address of HDMI registers */ | ||
76 | void __iomem *regs; | ||
77 | /** HDMI interrupt */ | ||
78 | unsigned int irq; | ||
79 | /** pointer to device parent */ | ||
80 | struct device *dev; | ||
81 | /** subdev generated by HDMI device */ | ||
82 | struct v4l2_subdev sd; | ||
83 | /** V4L2 device structure */ | ||
84 | struct v4l2_device v4l2_dev; | ||
85 | /** subdev of HDMIPHY interface */ | ||
86 | struct v4l2_subdev *phy_sd; | ||
87 | /** subdev of MHL interface */ | ||
88 | struct v4l2_subdev *mhl_sd; | ||
89 | /** configuration of current graphic mode */ | ||
90 | const struct hdmi_timings *cur_conf; | ||
91 | /** flag indicating that timings are dirty */ | ||
92 | int cur_conf_dirty; | ||
93 | /** current timings */ | ||
94 | struct v4l2_dv_timings cur_timings; | ||
95 | /** other resources */ | ||
96 | struct hdmi_resources res; | ||
97 | }; | ||
98 | |||
99 | static const struct platform_device_id hdmi_driver_types[] = { | ||
100 | { | ||
101 | .name = "s5pv210-hdmi", | ||
102 | }, { | ||
103 | .name = "exynos4-hdmi", | ||
104 | }, { | ||
105 | /* end node */ | ||
106 | } | ||
107 | }; | ||
108 | |||
109 | static const struct v4l2_subdev_ops hdmi_sd_ops; | ||
110 | |||
111 | static struct hdmi_device *sd_to_hdmi_dev(struct v4l2_subdev *sd) | ||
112 | { | ||
113 | return container_of(sd, struct hdmi_device, sd); | ||
114 | } | ||
115 | |||
116 | static inline | ||
117 | void hdmi_write(struct hdmi_device *hdev, u32 reg_id, u32 value) | ||
118 | { | ||
119 | writel(value, hdev->regs + reg_id); | ||
120 | } | ||
121 | |||
122 | static inline | ||
123 | void hdmi_write_mask(struct hdmi_device *hdev, u32 reg_id, u32 value, u32 mask) | ||
124 | { | ||
125 | u32 old = readl(hdev->regs + reg_id); | ||
126 | value = (value & mask) | (old & ~mask); | ||
127 | writel(value, hdev->regs + reg_id); | ||
128 | } | ||
129 | |||
130 | static inline | ||
131 | void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value) | ||
132 | { | ||
133 | writeb(value, hdev->regs + reg_id); | ||
134 | } | ||
135 | |||
136 | static inline | ||
137 | void hdmi_writebn(struct hdmi_device *hdev, u32 reg_id, int n, u32 value) | ||
138 | { | ||
139 | switch (n) { | ||
140 | default: | ||
141 | writeb(value >> 24, hdev->regs + reg_id + 12); | ||
142 | case 3: | ||
143 | writeb(value >> 16, hdev->regs + reg_id + 8); | ||
144 | case 2: | ||
145 | writeb(value >> 8, hdev->regs + reg_id + 4); | ||
146 | case 1: | ||
147 | writeb(value >> 0, hdev->regs + reg_id + 0); | ||
148 | } | ||
149 | } | ||
150 | |||
151 | static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id) | ||
152 | { | ||
153 | return readl(hdev->regs + reg_id); | ||
154 | } | ||
155 | |||
156 | static irqreturn_t hdmi_irq_handler(int irq, void *dev_data) | ||
157 | { | ||
158 | struct hdmi_device *hdev = dev_data; | ||
159 | u32 intc_flag; | ||
160 | |||
161 | (void)irq; | ||
162 | intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG); | ||
163 | /* clearing flags for HPD plug/unplug */ | ||
164 | if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) { | ||
165 | pr_info("unplugged\n"); | ||
166 | hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0, | ||
167 | HDMI_INTC_FLAG_HPD_UNPLUG); | ||
168 | } | ||
169 | if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) { | ||
170 | pr_info("plugged\n"); | ||
171 | hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0, | ||
172 | HDMI_INTC_FLAG_HPD_PLUG); | ||
173 | } | ||
174 | |||
175 | return IRQ_HANDLED; | ||
176 | } | ||
177 | |||
178 | static void hdmi_reg_init(struct hdmi_device *hdev) | ||
179 | { | ||
180 | /* enable HPD interrupts */ | ||
181 | hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL | | ||
182 | HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG); | ||
183 | /* choose DVI mode */ | ||
184 | hdmi_write_mask(hdev, HDMI_MODE_SEL, | ||
185 | HDMI_MODE_DVI_EN, HDMI_MODE_MASK); | ||
186 | hdmi_write_mask(hdev, HDMI_CON_2, ~0, | ||
187 | HDMI_DVI_PERAMBLE_EN | HDMI_DVI_BAND_EN); | ||
188 | /* disable bluescreen */ | ||
189 | hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN); | ||
190 | /* choose bluescreen (fecal) color */ | ||
191 | hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12); | ||
192 | hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34); | ||
193 | hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56); | ||
194 | } | ||
195 | |||
196 | static void hdmi_timing_apply(struct hdmi_device *hdev, | ||
197 | const struct hdmi_timings *t) | ||
198 | { | ||
199 | /* setting core registers */ | ||
200 | hdmi_writebn(hdev, HDMI_H_BLANK_0, 2, t->hact.beg); | ||
201 | hdmi_writebn(hdev, HDMI_H_SYNC_GEN_0, 3, | ||
202 | (t->hsyn_pol << 20) | (t->hsyn.end << 10) | t->hsyn.beg); | ||
203 | hdmi_writeb(hdev, HDMI_VSYNC_POL, t->vsyn_pol); | ||
204 | hdmi_writebn(hdev, HDMI_V_BLANK_0, 3, | ||
205 | (t->vact[0].beg << 11) | t->vact[0].end); | ||
206 | hdmi_writebn(hdev, HDMI_V_SYNC_GEN_1_0, 3, | ||
207 | (t->vsyn[0].beg << 12) | t->vsyn[0].end); | ||
208 | if (t->interlaced) { | ||
209 | u32 vsyn_trans = t->hsyn.beg + t->vsyn_off; | ||
210 | |||
211 | hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 1); | ||
212 | hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3, | ||
213 | (t->hact.end << 12) | t->vact[1].end); | ||
214 | hdmi_writebn(hdev, HDMI_V_BLANK_F_0, 3, | ||
215 | (t->vact[1].end << 11) | t->vact[1].beg); | ||
216 | hdmi_writebn(hdev, HDMI_V_SYNC_GEN_2_0, 3, | ||
217 | (t->vsyn[1].beg << 12) | t->vsyn[1].end); | ||
218 | hdmi_writebn(hdev, HDMI_V_SYNC_GEN_3_0, 3, | ||
219 | (vsyn_trans << 12) | vsyn_trans); | ||
220 | } else { | ||
221 | hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 0); | ||
222 | hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3, | ||
223 | (t->hact.end << 12) | t->vact[0].end); | ||
224 | } | ||
225 | |||
226 | /* Timing generator registers */ | ||
227 | hdmi_writebn(hdev, HDMI_TG_H_FSZ_L, 2, t->hact.end); | ||
228 | hdmi_writebn(hdev, HDMI_TG_HACT_ST_L, 2, t->hact.beg); | ||
229 | hdmi_writebn(hdev, HDMI_TG_HACT_SZ_L, 2, t->hact.end - t->hact.beg); | ||
230 | hdmi_writebn(hdev, HDMI_TG_VSYNC_L, 2, t->vsyn[0].beg); | ||
231 | hdmi_writebn(hdev, HDMI_TG_VACT_ST_L, 2, t->vact[0].beg); | ||
232 | hdmi_writebn(hdev, HDMI_TG_VACT_SZ_L, 2, | ||
233 | t->vact[0].end - t->vact[0].beg); | ||
234 | hdmi_writebn(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, 2, t->vsyn[0].beg); | ||
235 | hdmi_writebn(hdev, HDMI_TG_FIELD_TOP_HDMI_L, 2, t->vsyn[0].beg); | ||
236 | if (t->interlaced) { | ||
237 | hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_FIELD_EN); | ||
238 | hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[1].end); | ||
239 | hdmi_writebn(hdev, HDMI_TG_VSYNC2_L, 2, t->vsyn[1].beg); | ||
240 | hdmi_writebn(hdev, HDMI_TG_FIELD_CHG_L, 2, t->vact[0].end); | ||
241 | hdmi_writebn(hdev, HDMI_TG_VACT_ST2_L, 2, t->vact[1].beg); | ||
242 | hdmi_writebn(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, 2, t->vsyn[1].beg); | ||
243 | hdmi_writebn(hdev, HDMI_TG_FIELD_BOT_HDMI_L, 2, t->vsyn[1].beg); | ||
244 | } else { | ||
245 | hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_FIELD_EN); | ||
246 | hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[0].end); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | static int hdmi_conf_apply(struct hdmi_device *hdmi_dev) | ||
251 | { | ||
252 | struct device *dev = hdmi_dev->dev; | ||
253 | const struct hdmi_timings *conf = hdmi_dev->cur_conf; | ||
254 | int ret; | ||
255 | |||
256 | dev_dbg(dev, "%s\n", __func__); | ||
257 | |||
258 | /* skip if conf is already synchronized with HW */ | ||
259 | if (!hdmi_dev->cur_conf_dirty) | ||
260 | return 0; | ||
261 | |||
262 | /* reset hdmiphy */ | ||
263 | hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT); | ||
264 | mdelay(10); | ||
265 | hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT); | ||
266 | mdelay(10); | ||
267 | |||
268 | /* configure timings */ | ||
269 | ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_timings, | ||
270 | &hdmi_dev->cur_timings); | ||
271 | if (ret) { | ||
272 | dev_err(dev, "failed to set timings\n"); | ||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | /* resetting HDMI core */ | ||
277 | hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, 0, HDMI_CORE_SW_RSTOUT); | ||
278 | mdelay(10); | ||
279 | hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT); | ||
280 | mdelay(10); | ||
281 | |||
282 | hdmi_reg_init(hdmi_dev); | ||
283 | |||
284 | /* setting core registers */ | ||
285 | hdmi_timing_apply(hdmi_dev, conf); | ||
286 | |||
287 | hdmi_dev->cur_conf_dirty = 0; | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix) | ||
293 | { | ||
294 | #define DUMPREG(reg_id) \ | ||
295 | dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \ | ||
296 | readl(hdev->regs + reg_id)) | ||
297 | |||
298 | dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix); | ||
299 | DUMPREG(HDMI_INTC_FLAG); | ||
300 | DUMPREG(HDMI_INTC_CON); | ||
301 | DUMPREG(HDMI_HPD_STATUS); | ||
302 | DUMPREG(HDMI_PHY_RSTOUT); | ||
303 | DUMPREG(HDMI_PHY_VPLL); | ||
304 | DUMPREG(HDMI_PHY_CMU); | ||
305 | DUMPREG(HDMI_CORE_RSTOUT); | ||
306 | |||
307 | dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix); | ||
308 | DUMPREG(HDMI_CON_0); | ||
309 | DUMPREG(HDMI_CON_1); | ||
310 | DUMPREG(HDMI_CON_2); | ||
311 | DUMPREG(HDMI_SYS_STATUS); | ||
312 | DUMPREG(HDMI_PHY_STATUS); | ||
313 | DUMPREG(HDMI_STATUS_EN); | ||
314 | DUMPREG(HDMI_HPD); | ||
315 | DUMPREG(HDMI_MODE_SEL); | ||
316 | DUMPREG(HDMI_HPD_GEN); | ||
317 | DUMPREG(HDMI_DC_CONTROL); | ||
318 | DUMPREG(HDMI_VIDEO_PATTERN_GEN); | ||
319 | |||
320 | dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix); | ||
321 | DUMPREG(HDMI_H_BLANK_0); | ||
322 | DUMPREG(HDMI_H_BLANK_1); | ||
323 | DUMPREG(HDMI_V_BLANK_0); | ||
324 | DUMPREG(HDMI_V_BLANK_1); | ||
325 | DUMPREG(HDMI_V_BLANK_2); | ||
326 | DUMPREG(HDMI_H_V_LINE_0); | ||
327 | DUMPREG(HDMI_H_V_LINE_1); | ||
328 | DUMPREG(HDMI_H_V_LINE_2); | ||
329 | DUMPREG(HDMI_VSYNC_POL); | ||
330 | DUMPREG(HDMI_INT_PRO_MODE); | ||
331 | DUMPREG(HDMI_V_BLANK_F_0); | ||
332 | DUMPREG(HDMI_V_BLANK_F_1); | ||
333 | DUMPREG(HDMI_V_BLANK_F_2); | ||
334 | DUMPREG(HDMI_H_SYNC_GEN_0); | ||
335 | DUMPREG(HDMI_H_SYNC_GEN_1); | ||
336 | DUMPREG(HDMI_H_SYNC_GEN_2); | ||
337 | DUMPREG(HDMI_V_SYNC_GEN_1_0); | ||
338 | DUMPREG(HDMI_V_SYNC_GEN_1_1); | ||
339 | DUMPREG(HDMI_V_SYNC_GEN_1_2); | ||
340 | DUMPREG(HDMI_V_SYNC_GEN_2_0); | ||
341 | DUMPREG(HDMI_V_SYNC_GEN_2_1); | ||
342 | DUMPREG(HDMI_V_SYNC_GEN_2_2); | ||
343 | DUMPREG(HDMI_V_SYNC_GEN_3_0); | ||
344 | DUMPREG(HDMI_V_SYNC_GEN_3_1); | ||
345 | DUMPREG(HDMI_V_SYNC_GEN_3_2); | ||
346 | |||
347 | dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix); | ||
348 | DUMPREG(HDMI_TG_CMD); | ||
349 | DUMPREG(HDMI_TG_H_FSZ_L); | ||
350 | DUMPREG(HDMI_TG_H_FSZ_H); | ||
351 | DUMPREG(HDMI_TG_HACT_ST_L); | ||
352 | DUMPREG(HDMI_TG_HACT_ST_H); | ||
353 | DUMPREG(HDMI_TG_HACT_SZ_L); | ||
354 | DUMPREG(HDMI_TG_HACT_SZ_H); | ||
355 | DUMPREG(HDMI_TG_V_FSZ_L); | ||
356 | DUMPREG(HDMI_TG_V_FSZ_H); | ||
357 | DUMPREG(HDMI_TG_VSYNC_L); | ||
358 | DUMPREG(HDMI_TG_VSYNC_H); | ||
359 | DUMPREG(HDMI_TG_VSYNC2_L); | ||
360 | DUMPREG(HDMI_TG_VSYNC2_H); | ||
361 | DUMPREG(HDMI_TG_VACT_ST_L); | ||
362 | DUMPREG(HDMI_TG_VACT_ST_H); | ||
363 | DUMPREG(HDMI_TG_VACT_SZ_L); | ||
364 | DUMPREG(HDMI_TG_VACT_SZ_H); | ||
365 | DUMPREG(HDMI_TG_FIELD_CHG_L); | ||
366 | DUMPREG(HDMI_TG_FIELD_CHG_H); | ||
367 | DUMPREG(HDMI_TG_VACT_ST2_L); | ||
368 | DUMPREG(HDMI_TG_VACT_ST2_H); | ||
369 | DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L); | ||
370 | DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H); | ||
371 | DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L); | ||
372 | DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H); | ||
373 | DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L); | ||
374 | DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H); | ||
375 | DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L); | ||
376 | DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H); | ||
377 | #undef DUMPREG | ||
378 | } | ||
379 | |||
380 | static const struct hdmi_timings hdmi_timings_480p = { | ||
381 | .hact = { .beg = 138, .end = 858 }, | ||
382 | .hsyn_pol = 1, | ||
383 | .hsyn = { .beg = 16, .end = 16 + 62 }, | ||
384 | .interlaced = 0, | ||
385 | .vact[0] = { .beg = 42 + 3, .end = 522 + 3 }, | ||
386 | .vsyn_pol = 1, | ||
387 | .vsyn[0] = { .beg = 6 + 3, .end = 12 + 3}, | ||
388 | }; | ||
389 | |||
390 | static const struct hdmi_timings hdmi_timings_576p50 = { | ||
391 | .hact = { .beg = 144, .end = 864 }, | ||
392 | .hsyn_pol = 1, | ||
393 | .hsyn = { .beg = 12, .end = 12 + 64 }, | ||
394 | .interlaced = 0, | ||
395 | .vact[0] = { .beg = 44 + 5, .end = 620 + 5 }, | ||
396 | .vsyn_pol = 1, | ||
397 | .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5}, | ||
398 | }; | ||
399 | |||
400 | static const struct hdmi_timings hdmi_timings_720p60 = { | ||
401 | .hact = { .beg = 370, .end = 1650 }, | ||
402 | .hsyn_pol = 0, | ||
403 | .hsyn = { .beg = 110, .end = 110 + 40 }, | ||
404 | .interlaced = 0, | ||
405 | .vact[0] = { .beg = 25 + 5, .end = 745 + 5 }, | ||
406 | .vsyn_pol = 0, | ||
407 | .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5}, | ||
408 | }; | ||
409 | |||
410 | static const struct hdmi_timings hdmi_timings_720p50 = { | ||
411 | .hact = { .beg = 700, .end = 1980 }, | ||
412 | .hsyn_pol = 0, | ||
413 | .hsyn = { .beg = 440, .end = 440 + 40 }, | ||
414 | .interlaced = 0, | ||
415 | .vact[0] = { .beg = 25 + 5, .end = 745 + 5 }, | ||
416 | .vsyn_pol = 0, | ||
417 | .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5}, | ||
418 | }; | ||
419 | |||
420 | static const struct hdmi_timings hdmi_timings_1080p24 = { | ||
421 | .hact = { .beg = 830, .end = 2750 }, | ||
422 | .hsyn_pol = 0, | ||
423 | .hsyn = { .beg = 638, .end = 638 + 44 }, | ||
424 | .interlaced = 0, | ||
425 | .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 }, | ||
426 | .vsyn_pol = 0, | ||
427 | .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4}, | ||
428 | }; | ||
429 | |||
430 | static const struct hdmi_timings hdmi_timings_1080p60 = { | ||
431 | .hact = { .beg = 280, .end = 2200 }, | ||
432 | .hsyn_pol = 0, | ||
433 | .hsyn = { .beg = 88, .end = 88 + 44 }, | ||
434 | .interlaced = 0, | ||
435 | .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 }, | ||
436 | .vsyn_pol = 0, | ||
437 | .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4}, | ||
438 | }; | ||
439 | |||
440 | static const struct hdmi_timings hdmi_timings_1080i60 = { | ||
441 | .hact = { .beg = 280, .end = 2200 }, | ||
442 | .hsyn_pol = 0, | ||
443 | .hsyn = { .beg = 88, .end = 88 + 44 }, | ||
444 | .interlaced = 1, | ||
445 | .vact[0] = { .beg = 20 + 2, .end = 560 + 2 }, | ||
446 | .vact[1] = { .beg = 583 + 2, .end = 1123 + 2 }, | ||
447 | .vsyn_pol = 0, | ||
448 | .vsyn_off = 1100, | ||
449 | .vsyn[0] = { .beg = 0 + 2, .end = 5 + 2}, | ||
450 | .vsyn[1] = { .beg = 562 + 2, .end = 567 + 2}, | ||
451 | }; | ||
452 | |||
453 | static const struct hdmi_timings hdmi_timings_1080i50 = { | ||
454 | .hact = { .beg = 720, .end = 2640 }, | ||
455 | .hsyn_pol = 0, | ||
456 | .hsyn = { .beg = 528, .end = 528 + 44 }, | ||
457 | .interlaced = 1, | ||
458 | .vact[0] = { .beg = 20 + 2, .end = 560 + 2 }, | ||
459 | .vact[1] = { .beg = 583 + 2, .end = 1123 + 2 }, | ||
460 | .vsyn_pol = 0, | ||
461 | .vsyn_off = 1320, | ||
462 | .vsyn[0] = { .beg = 0 + 2, .end = 5 + 2}, | ||
463 | .vsyn[1] = { .beg = 562 + 2, .end = 567 + 2}, | ||
464 | }; | ||
465 | |||
466 | static const struct hdmi_timings hdmi_timings_1080p50 = { | ||
467 | .hact = { .beg = 720, .end = 2640 }, | ||
468 | .hsyn_pol = 0, | ||
469 | .hsyn = { .beg = 528, .end = 528 + 44 }, | ||
470 | .interlaced = 0, | ||
471 | .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 }, | ||
472 | .vsyn_pol = 0, | ||
473 | .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4}, | ||
474 | }; | ||
475 | |||
476 | /* default hdmi_timings index of the timings configured on probe */ | ||
477 | #define HDMI_DEFAULT_TIMINGS_IDX (0) | ||
478 | |||
479 | static const struct { | ||
480 | bool reduced_fps; | ||
481 | const struct v4l2_dv_timings dv_timings; | ||
482 | const struct hdmi_timings *hdmi_timings; | ||
483 | } hdmi_timings[] = { | ||
484 | { false, V4L2_DV_BT_CEA_720X480P59_94, &hdmi_timings_480p }, | ||
485 | { false, V4L2_DV_BT_CEA_720X576P50, &hdmi_timings_576p50 }, | ||
486 | { false, V4L2_DV_BT_CEA_1280X720P50, &hdmi_timings_720p50 }, | ||
487 | { true, V4L2_DV_BT_CEA_1280X720P60, &hdmi_timings_720p60 }, | ||
488 | { false, V4L2_DV_BT_CEA_1920X1080P24, &hdmi_timings_1080p24 }, | ||
489 | { false, V4L2_DV_BT_CEA_1920X1080P30, &hdmi_timings_1080p60 }, | ||
490 | { false, V4L2_DV_BT_CEA_1920X1080P50, &hdmi_timings_1080p50 }, | ||
491 | { false, V4L2_DV_BT_CEA_1920X1080I50, &hdmi_timings_1080i50 }, | ||
492 | { false, V4L2_DV_BT_CEA_1920X1080I60, &hdmi_timings_1080i60 }, | ||
493 | { false, V4L2_DV_BT_CEA_1920X1080P60, &hdmi_timings_1080p60 }, | ||
494 | }; | ||
495 | |||
496 | static int hdmi_streamon(struct hdmi_device *hdev) | ||
497 | { | ||
498 | struct device *dev = hdev->dev; | ||
499 | struct hdmi_resources *res = &hdev->res; | ||
500 | int ret, tries; | ||
501 | |||
502 | dev_dbg(dev, "%s\n", __func__); | ||
503 | |||
504 | ret = hdmi_conf_apply(hdev); | ||
505 | if (ret) | ||
506 | return ret; | ||
507 | |||
508 | ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1); | ||
509 | if (ret) | ||
510 | return ret; | ||
511 | |||
512 | /* waiting for HDMIPHY's PLL to get to steady state */ | ||
513 | for (tries = 100; tries; --tries) { | ||
514 | u32 val = hdmi_read(hdev, HDMI_PHY_STATUS); | ||
515 | if (val & HDMI_PHY_STATUS_READY) | ||
516 | break; | ||
517 | mdelay(1); | ||
518 | } | ||
519 | /* steady state not achieved */ | ||
520 | if (tries == 0) { | ||
521 | dev_err(dev, "hdmiphy's pll could not reach steady state.\n"); | ||
522 | v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); | ||
523 | hdmi_dumpregs(hdev, "hdmiphy - s_stream"); | ||
524 | return -EIO; | ||
525 | } | ||
526 | |||
527 | /* starting MHL */ | ||
528 | ret = v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 1); | ||
529 | if (hdev->mhl_sd && ret) { | ||
530 | v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); | ||
531 | hdmi_dumpregs(hdev, "mhl - s_stream"); | ||
532 | return -EIO; | ||
533 | } | ||
534 | |||
535 | /* hdmiphy clock is used for HDMI in streaming mode */ | ||
536 | clk_disable(res->sclk_hdmi); | ||
537 | clk_set_parent(res->sclk_hdmi, res->sclk_hdmiphy); | ||
538 | clk_enable(res->sclk_hdmi); | ||
539 | |||
540 | /* enable HDMI and timing generator */ | ||
541 | hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN); | ||
542 | hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_EN); | ||
543 | hdmi_dumpregs(hdev, "streamon"); | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static int hdmi_streamoff(struct hdmi_device *hdev) | ||
548 | { | ||
549 | struct device *dev = hdev->dev; | ||
550 | struct hdmi_resources *res = &hdev->res; | ||
551 | |||
552 | dev_dbg(dev, "%s\n", __func__); | ||
553 | |||
554 | hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN); | ||
555 | hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_EN); | ||
556 | |||
557 | /* pixel(vpll) clock is used for HDMI in config mode */ | ||
558 | clk_disable(res->sclk_hdmi); | ||
559 | clk_set_parent(res->sclk_hdmi, res->sclk_pixel); | ||
560 | clk_enable(res->sclk_hdmi); | ||
561 | |||
562 | v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 0); | ||
563 | v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); | ||
564 | |||
565 | hdmi_dumpregs(hdev, "streamoff"); | ||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | static int hdmi_s_stream(struct v4l2_subdev *sd, int enable) | ||
570 | { | ||
571 | struct hdmi_device *hdev = sd_to_hdmi_dev(sd); | ||
572 | struct device *dev = hdev->dev; | ||
573 | |||
574 | dev_dbg(dev, "%s(%d)\n", __func__, enable); | ||
575 | if (enable) | ||
576 | return hdmi_streamon(hdev); | ||
577 | return hdmi_streamoff(hdev); | ||
578 | } | ||
579 | |||
580 | static int hdmi_resource_poweron(struct hdmi_resources *res) | ||
581 | { | ||
582 | int ret; | ||
583 | |||
584 | /* turn HDMI power on */ | ||
585 | ret = regulator_bulk_enable(res->regul_count, res->regul_bulk); | ||
586 | if (ret < 0) | ||
587 | return ret; | ||
588 | /* power-on hdmi physical interface */ | ||
589 | clk_enable(res->hdmiphy); | ||
590 | /* use VPP as parent clock; HDMIPHY is not working yet */ | ||
591 | clk_set_parent(res->sclk_hdmi, res->sclk_pixel); | ||
592 | /* turn clocks on */ | ||
593 | clk_enable(res->sclk_hdmi); | ||
594 | |||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | static void hdmi_resource_poweroff(struct hdmi_resources *res) | ||
599 | { | ||
600 | /* turn clocks off */ | ||
601 | clk_disable(res->sclk_hdmi); | ||
602 | /* power-off hdmiphy */ | ||
603 | clk_disable(res->hdmiphy); | ||
604 | /* turn HDMI power off */ | ||
605 | regulator_bulk_disable(res->regul_count, res->regul_bulk); | ||
606 | } | ||
607 | |||
608 | static int hdmi_s_power(struct v4l2_subdev *sd, int on) | ||
609 | { | ||
610 | struct hdmi_device *hdev = sd_to_hdmi_dev(sd); | ||
611 | int ret; | ||
612 | |||
613 | if (on) | ||
614 | ret = pm_runtime_get_sync(hdev->dev); | ||
615 | else | ||
616 | ret = pm_runtime_put_sync(hdev->dev); | ||
617 | /* only values < 0 indicate errors */ | ||
618 | return ret < 0 ? ret : 0; | ||
619 | } | ||
620 | |||
621 | static int hdmi_s_dv_timings(struct v4l2_subdev *sd, | ||
622 | struct v4l2_dv_timings *timings) | ||
623 | { | ||
624 | struct hdmi_device *hdev = sd_to_hdmi_dev(sd); | ||
625 | struct device *dev = hdev->dev; | ||
626 | int i; | ||
627 | |||
628 | for (i = 0; i < ARRAY_SIZE(hdmi_timings); i++) | ||
629 | if (v4l2_match_dv_timings(&hdmi_timings[i].dv_timings, | ||
630 | timings, 0, false)) | ||
631 | break; | ||
632 | if (i == ARRAY_SIZE(hdmi_timings)) { | ||
633 | dev_err(dev, "timings not supported\n"); | ||
634 | return -EINVAL; | ||
635 | } | ||
636 | hdev->cur_conf = hdmi_timings[i].hdmi_timings; | ||
637 | hdev->cur_conf_dirty = 1; | ||
638 | hdev->cur_timings = *timings; | ||
639 | if (!hdmi_timings[i].reduced_fps) | ||
640 | hdev->cur_timings.bt.flags &= ~V4L2_DV_FL_CAN_REDUCE_FPS; | ||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static int hdmi_g_dv_timings(struct v4l2_subdev *sd, | ||
645 | struct v4l2_dv_timings *timings) | ||
646 | { | ||
647 | *timings = sd_to_hdmi_dev(sd)->cur_timings; | ||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | static int hdmi_get_fmt(struct v4l2_subdev *sd, | ||
652 | struct v4l2_subdev_pad_config *cfg, | ||
653 | struct v4l2_subdev_format *format) | ||
654 | { | ||
655 | struct v4l2_mbus_framefmt *fmt = &format->format; | ||
656 | struct hdmi_device *hdev = sd_to_hdmi_dev(sd); | ||
657 | const struct hdmi_timings *t = hdev->cur_conf; | ||
658 | |||
659 | dev_dbg(hdev->dev, "%s\n", __func__); | ||
660 | if (!hdev->cur_conf) | ||
661 | return -EINVAL; | ||
662 | if (format->pad) | ||
663 | return -EINVAL; | ||
664 | |||
665 | memset(fmt, 0, sizeof(*fmt)); | ||
666 | fmt->width = t->hact.end - t->hact.beg; | ||
667 | fmt->height = t->vact[0].end - t->vact[0].beg; | ||
668 | fmt->code = MEDIA_BUS_FMT_FIXED; /* means RGB888 */ | ||
669 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | ||
670 | if (t->interlaced) { | ||
671 | fmt->field = V4L2_FIELD_INTERLACED; | ||
672 | fmt->height *= 2; | ||
673 | } else { | ||
674 | fmt->field = V4L2_FIELD_NONE; | ||
675 | } | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static int hdmi_enum_dv_timings(struct v4l2_subdev *sd, | ||
680 | struct v4l2_enum_dv_timings *timings) | ||
681 | { | ||
682 | if (timings->pad != 0) | ||
683 | return -EINVAL; | ||
684 | if (timings->index >= ARRAY_SIZE(hdmi_timings)) | ||
685 | return -EINVAL; | ||
686 | timings->timings = hdmi_timings[timings->index].dv_timings; | ||
687 | if (!hdmi_timings[timings->index].reduced_fps) | ||
688 | timings->timings.bt.flags &= ~V4L2_DV_FL_CAN_REDUCE_FPS; | ||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | static int hdmi_dv_timings_cap(struct v4l2_subdev *sd, | ||
693 | struct v4l2_dv_timings_cap *cap) | ||
694 | { | ||
695 | struct hdmi_device *hdev = sd_to_hdmi_dev(sd); | ||
696 | |||
697 | if (cap->pad != 0) | ||
698 | return -EINVAL; | ||
699 | |||
700 | /* Let the phy fill in the pixelclock range */ | ||
701 | v4l2_subdev_call(hdev->phy_sd, pad, dv_timings_cap, cap); | ||
702 | cap->type = V4L2_DV_BT_656_1120; | ||
703 | cap->bt.min_width = 720; | ||
704 | cap->bt.max_width = 1920; | ||
705 | cap->bt.min_height = 480; | ||
706 | cap->bt.max_height = 1080; | ||
707 | cap->bt.standards = V4L2_DV_BT_STD_CEA861; | ||
708 | cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | | ||
709 | V4L2_DV_BT_CAP_PROGRESSIVE; | ||
710 | return 0; | ||
711 | } | ||
712 | |||
713 | static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = { | ||
714 | .s_power = hdmi_s_power, | ||
715 | }; | ||
716 | |||
717 | static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = { | ||
718 | .s_dv_timings = hdmi_s_dv_timings, | ||
719 | .g_dv_timings = hdmi_g_dv_timings, | ||
720 | .s_stream = hdmi_s_stream, | ||
721 | }; | ||
722 | |||
723 | static const struct v4l2_subdev_pad_ops hdmi_sd_pad_ops = { | ||
724 | .enum_dv_timings = hdmi_enum_dv_timings, | ||
725 | .dv_timings_cap = hdmi_dv_timings_cap, | ||
726 | .get_fmt = hdmi_get_fmt, | ||
727 | }; | ||
728 | |||
729 | static const struct v4l2_subdev_ops hdmi_sd_ops = { | ||
730 | .core = &hdmi_sd_core_ops, | ||
731 | .video = &hdmi_sd_video_ops, | ||
732 | .pad = &hdmi_sd_pad_ops, | ||
733 | }; | ||
734 | |||
735 | static int hdmi_runtime_suspend(struct device *dev) | ||
736 | { | ||
737 | struct v4l2_subdev *sd = dev_get_drvdata(dev); | ||
738 | struct hdmi_device *hdev = sd_to_hdmi_dev(sd); | ||
739 | |||
740 | dev_dbg(dev, "%s\n", __func__); | ||
741 | v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0); | ||
742 | hdmi_resource_poweroff(&hdev->res); | ||
743 | /* flag that device context is lost */ | ||
744 | hdev->cur_conf_dirty = 1; | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | static int hdmi_runtime_resume(struct device *dev) | ||
749 | { | ||
750 | struct v4l2_subdev *sd = dev_get_drvdata(dev); | ||
751 | struct hdmi_device *hdev = sd_to_hdmi_dev(sd); | ||
752 | int ret; | ||
753 | |||
754 | dev_dbg(dev, "%s\n", __func__); | ||
755 | |||
756 | ret = hdmi_resource_poweron(&hdev->res); | ||
757 | if (ret < 0) | ||
758 | return ret; | ||
759 | |||
760 | /* starting MHL */ | ||
761 | ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1); | ||
762 | if (hdev->mhl_sd && ret) | ||
763 | goto fail; | ||
764 | |||
765 | dev_dbg(dev, "poweron succeed\n"); | ||
766 | |||
767 | return 0; | ||
768 | |||
769 | fail: | ||
770 | hdmi_resource_poweroff(&hdev->res); | ||
771 | dev_err(dev, "poweron failed\n"); | ||
772 | |||
773 | return ret; | ||
774 | } | ||
775 | |||
776 | static const struct dev_pm_ops hdmi_pm_ops = { | ||
777 | .runtime_suspend = hdmi_runtime_suspend, | ||
778 | .runtime_resume = hdmi_runtime_resume, | ||
779 | }; | ||
780 | |||
781 | static void hdmi_resource_clear_clocks(struct hdmi_resources *res) | ||
782 | { | ||
783 | res->hdmi = ERR_PTR(-EINVAL); | ||
784 | res->sclk_hdmi = ERR_PTR(-EINVAL); | ||
785 | res->sclk_pixel = ERR_PTR(-EINVAL); | ||
786 | res->sclk_hdmiphy = ERR_PTR(-EINVAL); | ||
787 | res->hdmiphy = ERR_PTR(-EINVAL); | ||
788 | } | ||
789 | |||
790 | static void hdmi_resources_cleanup(struct hdmi_device *hdev) | ||
791 | { | ||
792 | struct hdmi_resources *res = &hdev->res; | ||
793 | |||
794 | dev_dbg(hdev->dev, "HDMI resource cleanup\n"); | ||
795 | /* put clocks, power */ | ||
796 | if (res->regul_count) | ||
797 | regulator_bulk_free(res->regul_count, res->regul_bulk); | ||
798 | /* kfree is NULL-safe */ | ||
799 | kfree(res->regul_bulk); | ||
800 | if (!IS_ERR(res->hdmiphy)) | ||
801 | clk_put(res->hdmiphy); | ||
802 | if (!IS_ERR(res->sclk_hdmiphy)) | ||
803 | clk_put(res->sclk_hdmiphy); | ||
804 | if (!IS_ERR(res->sclk_pixel)) | ||
805 | clk_put(res->sclk_pixel); | ||
806 | if (!IS_ERR(res->sclk_hdmi)) | ||
807 | clk_put(res->sclk_hdmi); | ||
808 | if (!IS_ERR(res->hdmi)) | ||
809 | clk_put(res->hdmi); | ||
810 | memset(res, 0, sizeof(*res)); | ||
811 | hdmi_resource_clear_clocks(res); | ||
812 | } | ||
813 | |||
814 | static int hdmi_resources_init(struct hdmi_device *hdev) | ||
815 | { | ||
816 | struct device *dev = hdev->dev; | ||
817 | struct hdmi_resources *res = &hdev->res; | ||
818 | static char *supply[] = { | ||
819 | "hdmi-en", | ||
820 | "vdd", | ||
821 | "vdd_osc", | ||
822 | "vdd_pll", | ||
823 | }; | ||
824 | int i, ret; | ||
825 | |||
826 | dev_dbg(dev, "HDMI resource init\n"); | ||
827 | |||
828 | memset(res, 0, sizeof(*res)); | ||
829 | hdmi_resource_clear_clocks(res); | ||
830 | |||
831 | /* get clocks, power */ | ||
832 | res->hdmi = clk_get(dev, "hdmi"); | ||
833 | if (IS_ERR(res->hdmi)) { | ||
834 | dev_err(dev, "failed to get clock 'hdmi'\n"); | ||
835 | goto fail; | ||
836 | } | ||
837 | res->sclk_hdmi = clk_get(dev, "sclk_hdmi"); | ||
838 | if (IS_ERR(res->sclk_hdmi)) { | ||
839 | dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); | ||
840 | goto fail; | ||
841 | } | ||
842 | res->sclk_pixel = clk_get(dev, "sclk_pixel"); | ||
843 | if (IS_ERR(res->sclk_pixel)) { | ||
844 | dev_err(dev, "failed to get clock 'sclk_pixel'\n"); | ||
845 | goto fail; | ||
846 | } | ||
847 | res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy"); | ||
848 | if (IS_ERR(res->sclk_hdmiphy)) { | ||
849 | dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n"); | ||
850 | goto fail; | ||
851 | } | ||
852 | res->hdmiphy = clk_get(dev, "hdmiphy"); | ||
853 | if (IS_ERR(res->hdmiphy)) { | ||
854 | dev_err(dev, "failed to get clock 'hdmiphy'\n"); | ||
855 | goto fail; | ||
856 | } | ||
857 | res->regul_bulk = kcalloc(ARRAY_SIZE(supply), | ||
858 | sizeof(res->regul_bulk[0]), GFP_KERNEL); | ||
859 | if (!res->regul_bulk) { | ||
860 | dev_err(dev, "failed to get memory for regulators\n"); | ||
861 | goto fail; | ||
862 | } | ||
863 | for (i = 0; i < ARRAY_SIZE(supply); ++i) { | ||
864 | res->regul_bulk[i].supply = supply[i]; | ||
865 | res->regul_bulk[i].consumer = NULL; | ||
866 | } | ||
867 | |||
868 | ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk); | ||
869 | if (ret) { | ||
870 | dev_err(dev, "failed to get regulators\n"); | ||
871 | goto fail; | ||
872 | } | ||
873 | res->regul_count = ARRAY_SIZE(supply); | ||
874 | |||
875 | return 0; | ||
876 | fail: | ||
877 | dev_err(dev, "HDMI resource init - failed\n"); | ||
878 | hdmi_resources_cleanup(hdev); | ||
879 | return -ENODEV; | ||
880 | } | ||
881 | |||
882 | static int hdmi_probe(struct platform_device *pdev) | ||
883 | { | ||
884 | struct device *dev = &pdev->dev; | ||
885 | struct resource *res; | ||
886 | struct i2c_adapter *adapter; | ||
887 | struct v4l2_subdev *sd; | ||
888 | struct hdmi_device *hdmi_dev = NULL; | ||
889 | struct s5p_hdmi_platform_data *pdata = dev->platform_data; | ||
890 | int ret; | ||
891 | |||
892 | dev_dbg(dev, "probe start\n"); | ||
893 | |||
894 | if (!pdata) { | ||
895 | dev_err(dev, "platform data is missing\n"); | ||
896 | ret = -ENODEV; | ||
897 | goto fail; | ||
898 | } | ||
899 | |||
900 | hdmi_dev = devm_kzalloc(&pdev->dev, sizeof(*hdmi_dev), GFP_KERNEL); | ||
901 | if (!hdmi_dev) { | ||
902 | dev_err(dev, "out of memory\n"); | ||
903 | ret = -ENOMEM; | ||
904 | goto fail; | ||
905 | } | ||
906 | |||
907 | hdmi_dev->dev = dev; | ||
908 | |||
909 | ret = hdmi_resources_init(hdmi_dev); | ||
910 | if (ret) | ||
911 | goto fail; | ||
912 | |||
913 | /* mapping HDMI registers */ | ||
914 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
915 | if (res == NULL) { | ||
916 | dev_err(dev, "get memory resource failed.\n"); | ||
917 | ret = -ENXIO; | ||
918 | goto fail_init; | ||
919 | } | ||
920 | |||
921 | hdmi_dev->regs = devm_ioremap(&pdev->dev, res->start, | ||
922 | resource_size(res)); | ||
923 | if (hdmi_dev->regs == NULL) { | ||
924 | dev_err(dev, "register mapping failed.\n"); | ||
925 | ret = -ENXIO; | ||
926 | goto fail_init; | ||
927 | } | ||
928 | |||
929 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
930 | if (res == NULL) { | ||
931 | dev_err(dev, "get interrupt resource failed.\n"); | ||
932 | ret = -ENXIO; | ||
933 | goto fail_init; | ||
934 | } | ||
935 | |||
936 | ret = devm_request_irq(&pdev->dev, res->start, hdmi_irq_handler, 0, | ||
937 | "hdmi", hdmi_dev); | ||
938 | if (ret) { | ||
939 | dev_err(dev, "request interrupt failed.\n"); | ||
940 | goto fail_init; | ||
941 | } | ||
942 | hdmi_dev->irq = res->start; | ||
943 | |||
944 | /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */ | ||
945 | strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev), | ||
946 | sizeof(hdmi_dev->v4l2_dev.name)); | ||
947 | /* passing NULL owner prevents driver from erasing drvdata */ | ||
948 | ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev); | ||
949 | if (ret) { | ||
950 | dev_err(dev, "could not register v4l2 device.\n"); | ||
951 | goto fail_init; | ||
952 | } | ||
953 | |||
954 | /* testing if hdmiphy info is present */ | ||
955 | if (!pdata->hdmiphy_info) { | ||
956 | dev_err(dev, "hdmiphy info is missing in platform data\n"); | ||
957 | ret = -ENXIO; | ||
958 | goto fail_vdev; | ||
959 | } | ||
960 | |||
961 | adapter = i2c_get_adapter(pdata->hdmiphy_bus); | ||
962 | if (adapter == NULL) { | ||
963 | dev_err(dev, "hdmiphy adapter request failed\n"); | ||
964 | ret = -ENXIO; | ||
965 | goto fail_vdev; | ||
966 | } | ||
967 | |||
968 | hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev, | ||
969 | adapter, pdata->hdmiphy_info, NULL); | ||
970 | /* on failure or not adapter is no longer useful */ | ||
971 | i2c_put_adapter(adapter); | ||
972 | if (hdmi_dev->phy_sd == NULL) { | ||
973 | dev_err(dev, "missing subdev for hdmiphy\n"); | ||
974 | ret = -ENODEV; | ||
975 | goto fail_vdev; | ||
976 | } | ||
977 | |||
978 | /* initialization of MHL interface if present */ | ||
979 | if (pdata->mhl_info) { | ||
980 | adapter = i2c_get_adapter(pdata->mhl_bus); | ||
981 | if (adapter == NULL) { | ||
982 | dev_err(dev, "MHL adapter request failed\n"); | ||
983 | ret = -ENXIO; | ||
984 | goto fail_vdev; | ||
985 | } | ||
986 | |||
987 | hdmi_dev->mhl_sd = v4l2_i2c_new_subdev_board( | ||
988 | &hdmi_dev->v4l2_dev, adapter, | ||
989 | pdata->mhl_info, NULL); | ||
990 | /* on failure or not adapter is no longer useful */ | ||
991 | i2c_put_adapter(adapter); | ||
992 | if (hdmi_dev->mhl_sd == NULL) { | ||
993 | dev_err(dev, "missing subdev for MHL\n"); | ||
994 | ret = -ENODEV; | ||
995 | goto fail_vdev; | ||
996 | } | ||
997 | } | ||
998 | |||
999 | clk_enable(hdmi_dev->res.hdmi); | ||
1000 | |||
1001 | pm_runtime_enable(dev); | ||
1002 | |||
1003 | sd = &hdmi_dev->sd; | ||
1004 | v4l2_subdev_init(sd, &hdmi_sd_ops); | ||
1005 | sd->owner = THIS_MODULE; | ||
1006 | |||
1007 | strlcpy(sd->name, "s5p-hdmi", sizeof(sd->name)); | ||
1008 | hdmi_dev->cur_timings = | ||
1009 | hdmi_timings[HDMI_DEFAULT_TIMINGS_IDX].dv_timings; | ||
1010 | /* FIXME: missing fail timings is not supported */ | ||
1011 | hdmi_dev->cur_conf = | ||
1012 | hdmi_timings[HDMI_DEFAULT_TIMINGS_IDX].hdmi_timings; | ||
1013 | hdmi_dev->cur_conf_dirty = 1; | ||
1014 | |||
1015 | /* storing subdev for call that have only access to struct device */ | ||
1016 | dev_set_drvdata(dev, sd); | ||
1017 | |||
1018 | dev_info(dev, "probe successful\n"); | ||
1019 | |||
1020 | return 0; | ||
1021 | |||
1022 | fail_vdev: | ||
1023 | v4l2_device_unregister(&hdmi_dev->v4l2_dev); | ||
1024 | |||
1025 | fail_init: | ||
1026 | hdmi_resources_cleanup(hdmi_dev); | ||
1027 | |||
1028 | fail: | ||
1029 | dev_err(dev, "probe failed\n"); | ||
1030 | return ret; | ||
1031 | } | ||
1032 | |||
1033 | static int hdmi_remove(struct platform_device *pdev) | ||
1034 | { | ||
1035 | struct device *dev = &pdev->dev; | ||
1036 | struct v4l2_subdev *sd = dev_get_drvdata(dev); | ||
1037 | struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd); | ||
1038 | |||
1039 | pm_runtime_disable(dev); | ||
1040 | clk_disable(hdmi_dev->res.hdmi); | ||
1041 | v4l2_device_unregister(&hdmi_dev->v4l2_dev); | ||
1042 | disable_irq(hdmi_dev->irq); | ||
1043 | hdmi_resources_cleanup(hdmi_dev); | ||
1044 | dev_info(dev, "remove successful\n"); | ||
1045 | |||
1046 | return 0; | ||
1047 | } | ||
1048 | |||
1049 | static struct platform_driver hdmi_driver __refdata = { | ||
1050 | .probe = hdmi_probe, | ||
1051 | .remove = hdmi_remove, | ||
1052 | .id_table = hdmi_driver_types, | ||
1053 | .driver = { | ||
1054 | .name = "s5p-hdmi", | ||
1055 | .pm = &hdmi_pm_ops, | ||
1056 | } | ||
1057 | }; | ||
1058 | |||
1059 | module_platform_driver(hdmi_driver); | ||
diff --git a/drivers/media/platform/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c deleted file mode 100644 index aae652351aa8..000000000000 --- a/drivers/media/platform/s5p-tv/hdmiphy_drv.c +++ /dev/null | |||
@@ -1,324 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung HDMI Physical interface driver | ||
3 | * | ||
4 | * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd | ||
5 | * Author: Tomasz Stanislawski <t.stanislaws@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/err.h> | ||
21 | |||
22 | #include <media/v4l2-subdev.h> | ||
23 | |||
24 | MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>"); | ||
25 | MODULE_DESCRIPTION("Samsung HDMI Physical interface driver"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | |||
28 | struct hdmiphy_conf { | ||
29 | unsigned long pixclk; | ||
30 | const u8 *data; | ||
31 | }; | ||
32 | |||
33 | struct hdmiphy_ctx { | ||
34 | struct v4l2_subdev sd; | ||
35 | const struct hdmiphy_conf *conf_tab; | ||
36 | }; | ||
37 | |||
38 | static const struct hdmiphy_conf hdmiphy_conf_s5pv210[] = { | ||
39 | { .pixclk = 27000000, .data = (u8 [32]) { | ||
40 | 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, | ||
41 | 0x6B, 0x10, 0x02, 0x52, 0xDF, 0xF2, 0x54, 0x87, | ||
42 | 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||
43 | 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, } | ||
44 | }, | ||
45 | { .pixclk = 27027000, .data = (u8 [32]) { | ||
46 | 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64, | ||
47 | 0x6B, 0x10, 0x02, 0x52, 0xDF, 0xF2, 0x54, 0x87, | ||
48 | 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||
49 | 0x22, 0x40, 0xE2, 0x26, 0x00, 0x00, 0x00, 0x00, } | ||
50 | }, | ||
51 | { .pixclk = 74176000, .data = (u8 [32]) { | ||
52 | 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B, | ||
53 | 0x6D, 0x10, 0x01, 0x52, 0xEF, 0xF3, 0x54, 0xB9, | ||
54 | 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||
55 | 0x22, 0x40, 0xA5, 0x26, 0x01, 0x00, 0x00, 0x00, } | ||
56 | }, | ||
57 | { .pixclk = 74250000, .data = (u8 [32]) { | ||
58 | 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40, | ||
59 | 0x6A, 0x10, 0x01, 0x52, 0xFF, 0xF1, 0x54, 0xBA, | ||
60 | 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||
61 | 0x22, 0x40, 0xA4, 0x26, 0x01, 0x00, 0x00, 0x00, } | ||
62 | }, | ||
63 | { /* end marker */ } | ||
64 | }; | ||
65 | |||
66 | static const struct hdmiphy_conf hdmiphy_conf_exynos4210[] = { | ||
67 | { .pixclk = 27000000, .data = (u8 [32]) { | ||
68 | 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, | ||
69 | 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87, | ||
70 | 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||
71 | 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, } | ||
72 | }, | ||
73 | { .pixclk = 27027000, .data = (u8 [32]) { | ||
74 | 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64, | ||
75 | 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87, | ||
76 | 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||
77 | 0x22, 0x40, 0xE2, 0x26, 0x00, 0x00, 0x00, 0x00, } | ||
78 | }, | ||
79 | { .pixclk = 74176000, .data = (u8 [32]) { | ||
80 | 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B, | ||
81 | 0x6D, 0x10, 0x01, 0x51, 0xEF, 0xF3, 0x54, 0xB9, | ||
82 | 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||
83 | 0x22, 0x40, 0xA5, 0x26, 0x01, 0x00, 0x00, 0x00, } | ||
84 | }, | ||
85 | { .pixclk = 74250000, .data = (u8 [32]) { | ||
86 | 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40, | ||
87 | 0x6A, 0x10, 0x01, 0x51, 0xFF, 0xF1, 0x54, 0xBA, | ||
88 | 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||
89 | 0x22, 0x40, 0xA4, 0x26, 0x01, 0x00, 0x00, 0x00, } | ||
90 | }, | ||
91 | { .pixclk = 148352000, .data = (u8 [32]) { | ||
92 | 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B, | ||
93 | 0x6D, 0x18, 0x00, 0x51, 0xEF, 0xF3, 0x54, 0xB9, | ||
94 | 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||
95 | 0x11, 0x40, 0xA5, 0x26, 0x02, 0x00, 0x00, 0x00, } | ||
96 | }, | ||
97 | { .pixclk = 148500000, .data = (u8 [32]) { | ||
98 | 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40, | ||
99 | 0x6A, 0x18, 0x00, 0x51, 0xFF, 0xF1, 0x54, 0xBA, | ||
100 | 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||
101 | 0x11, 0x40, 0xA4, 0x26, 0x02, 0x00, 0x00, 0x00, } | ||
102 | }, | ||
103 | { /* end marker */ } | ||
104 | }; | ||
105 | |||
106 | static const struct hdmiphy_conf hdmiphy_conf_exynos4212[] = { | ||
107 | { .pixclk = 27000000, .data = (u8 [32]) { | ||
108 | 0x01, 0x11, 0x2D, 0x75, 0x00, 0x01, 0x00, 0x08, | ||
109 | 0x82, 0x00, 0x0E, 0xD9, 0x45, 0xA0, 0x34, 0xC0, | ||
110 | 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x71, | ||
111 | 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, } | ||
112 | }, | ||
113 | { .pixclk = 27027000, .data = (u8 [32]) { | ||
114 | 0x01, 0x91, 0x2D, 0x72, 0x00, 0x64, 0x12, 0x08, | ||
115 | 0x43, 0x20, 0x0E, 0xD9, 0x45, 0xA0, 0x34, 0xC0, | ||
116 | 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x71, | ||
117 | 0x54, 0xE2, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, } | ||
118 | }, | ||
119 | { .pixclk = 74176000, .data = (u8 [32]) { | ||
120 | 0x01, 0x91, 0x3E, 0x35, 0x00, 0x5B, 0xDE, 0x08, | ||
121 | 0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0, | ||
122 | 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x52, | ||
123 | 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, } | ||
124 | }, | ||
125 | { .pixclk = 74250000, .data = (u8 [32]) { | ||
126 | 0x01, 0x91, 0x3E, 0x35, 0x00, 0x40, 0xF0, 0x08, | ||
127 | 0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0, | ||
128 | 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x52, | ||
129 | 0x54, 0xA4, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, } | ||
130 | }, | ||
131 | { .pixclk = 148500000, .data = (u8 [32]) { | ||
132 | 0x01, 0x91, 0x3E, 0x15, 0x00, 0x40, 0xF0, 0x08, | ||
133 | 0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0, | ||
134 | 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0xA4, | ||
135 | 0x54, 0x4A, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, } | ||
136 | }, | ||
137 | { /* end marker */ } | ||
138 | }; | ||
139 | |||
140 | static const struct hdmiphy_conf hdmiphy_conf_exynos4412[] = { | ||
141 | { .pixclk = 27000000, .data = (u8 [32]) { | ||
142 | 0x01, 0x11, 0x2D, 0x75, 0x40, 0x01, 0x00, 0x08, | ||
143 | 0x82, 0x00, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, | ||
144 | 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86, | ||
145 | 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, } | ||
146 | }, | ||
147 | { .pixclk = 27027000, .data = (u8 [32]) { | ||
148 | 0x01, 0x91, 0x2D, 0x72, 0x40, 0x64, 0x12, 0x08, | ||
149 | 0x43, 0x20, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80, | ||
150 | 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86, | ||
151 | 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, } | ||
152 | }, | ||
153 | { .pixclk = 74176000, .data = (u8 [32]) { | ||
154 | 0x01, 0x91, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0x08, | ||
155 | 0x81, 0x20, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80, | ||
156 | 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86, | ||
157 | 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, } | ||
158 | }, | ||
159 | { .pixclk = 74250000, .data = (u8 [32]) { | ||
160 | 0x01, 0x91, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08, | ||
161 | 0x81, 0x20, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80, | ||
162 | 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86, | ||
163 | 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, } | ||
164 | }, | ||
165 | { .pixclk = 148500000, .data = (u8 [32]) { | ||
166 | 0x01, 0x91, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08, | ||
167 | 0x81, 0x20, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80, | ||
168 | 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86, | ||
169 | 0x54, 0x4B, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, } | ||
170 | }, | ||
171 | { /* end marker */ } | ||
172 | }; | ||
173 | |||
174 | static inline struct hdmiphy_ctx *sd_to_ctx(struct v4l2_subdev *sd) | ||
175 | { | ||
176 | return container_of(sd, struct hdmiphy_ctx, sd); | ||
177 | } | ||
178 | |||
179 | static const u8 *hdmiphy_find_conf(unsigned long pixclk, | ||
180 | const struct hdmiphy_conf *conf) | ||
181 | { | ||
182 | for (; conf->pixclk; ++conf) | ||
183 | if (conf->pixclk == pixclk) | ||
184 | return conf->data; | ||
185 | return NULL; | ||
186 | } | ||
187 | |||
188 | static int hdmiphy_s_power(struct v4l2_subdev *sd, int on) | ||
189 | { | ||
190 | /* to be implemented */ | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int hdmiphy_s_dv_timings(struct v4l2_subdev *sd, | ||
195 | struct v4l2_dv_timings *timings) | ||
196 | { | ||
197 | const u8 *data; | ||
198 | u8 buffer[32]; | ||
199 | int ret; | ||
200 | struct hdmiphy_ctx *ctx = sd_to_ctx(sd); | ||
201 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
202 | struct device *dev = &client->dev; | ||
203 | unsigned long pixclk = timings->bt.pixelclock; | ||
204 | |||
205 | dev_info(dev, "s_dv_timings\n"); | ||
206 | if ((timings->bt.flags & V4L2_DV_FL_REDUCED_FPS) && pixclk == 74250000) | ||
207 | pixclk = 74176000; | ||
208 | data = hdmiphy_find_conf(pixclk, ctx->conf_tab); | ||
209 | if (!data) { | ||
210 | dev_err(dev, "format not supported\n"); | ||
211 | return -EINVAL; | ||
212 | } | ||
213 | |||
214 | /* storing configuration to the device */ | ||
215 | memcpy(buffer, data, 32); | ||
216 | ret = i2c_master_send(client, buffer, 32); | ||
217 | if (ret != 32) { | ||
218 | dev_err(dev, "failed to configure HDMIPHY via I2C\n"); | ||
219 | return -EIO; | ||
220 | } | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int hdmiphy_dv_timings_cap(struct v4l2_subdev *sd, | ||
226 | struct v4l2_dv_timings_cap *cap) | ||
227 | { | ||
228 | if (cap->pad != 0) | ||
229 | return -EINVAL; | ||
230 | |||
231 | cap->type = V4L2_DV_BT_656_1120; | ||
232 | /* The phy only determines the pixelclock, leave the other values | ||
233 | * at 0 to signify that we have no information for them. */ | ||
234 | cap->bt.min_pixelclock = 27000000; | ||
235 | cap->bt.max_pixelclock = 148500000; | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable) | ||
240 | { | ||
241 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
242 | struct device *dev = &client->dev; | ||
243 | u8 buffer[2]; | ||
244 | int ret; | ||
245 | |||
246 | dev_info(dev, "s_stream(%d)\n", enable); | ||
247 | /* going to/from configuration from/to operation mode */ | ||
248 | buffer[0] = 0x1f; | ||
249 | buffer[1] = enable ? 0x80 : 0x00; | ||
250 | |||
251 | ret = i2c_master_send(client, buffer, 2); | ||
252 | if (ret != 2) { | ||
253 | dev_err(dev, "stream (%d) failed\n", enable); | ||
254 | return -EIO; | ||
255 | } | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static const struct v4l2_subdev_core_ops hdmiphy_core_ops = { | ||
260 | .s_power = hdmiphy_s_power, | ||
261 | }; | ||
262 | |||
263 | static const struct v4l2_subdev_video_ops hdmiphy_video_ops = { | ||
264 | .s_dv_timings = hdmiphy_s_dv_timings, | ||
265 | .s_stream = hdmiphy_s_stream, | ||
266 | }; | ||
267 | |||
268 | static const struct v4l2_subdev_pad_ops hdmiphy_pad_ops = { | ||
269 | .dv_timings_cap = hdmiphy_dv_timings_cap, | ||
270 | }; | ||
271 | |||
272 | static const struct v4l2_subdev_ops hdmiphy_ops = { | ||
273 | .core = &hdmiphy_core_ops, | ||
274 | .video = &hdmiphy_video_ops, | ||
275 | .pad = &hdmiphy_pad_ops, | ||
276 | }; | ||
277 | |||
278 | static int hdmiphy_probe(struct i2c_client *client, | ||
279 | const struct i2c_device_id *id) | ||
280 | { | ||
281 | struct hdmiphy_ctx *ctx; | ||
282 | |||
283 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | ||
284 | if (!ctx) | ||
285 | return -ENOMEM; | ||
286 | |||
287 | ctx->conf_tab = (struct hdmiphy_conf *)id->driver_data; | ||
288 | v4l2_i2c_subdev_init(&ctx->sd, client, &hdmiphy_ops); | ||
289 | |||
290 | dev_info(&client->dev, "probe successful\n"); | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int hdmiphy_remove(struct i2c_client *client) | ||
295 | { | ||
296 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
297 | struct hdmiphy_ctx *ctx = sd_to_ctx(sd); | ||
298 | |||
299 | kfree(ctx); | ||
300 | dev_info(&client->dev, "remove successful\n"); | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static const struct i2c_device_id hdmiphy_id[] = { | ||
306 | { "hdmiphy", (unsigned long)hdmiphy_conf_exynos4210 }, | ||
307 | { "hdmiphy-s5pv210", (unsigned long)hdmiphy_conf_s5pv210 }, | ||
308 | { "hdmiphy-exynos4210", (unsigned long)hdmiphy_conf_exynos4210 }, | ||
309 | { "hdmiphy-exynos4212", (unsigned long)hdmiphy_conf_exynos4212 }, | ||
310 | { "hdmiphy-exynos4412", (unsigned long)hdmiphy_conf_exynos4412 }, | ||
311 | { }, | ||
312 | }; | ||
313 | MODULE_DEVICE_TABLE(i2c, hdmiphy_id); | ||
314 | |||
315 | static struct i2c_driver hdmiphy_driver = { | ||
316 | .driver = { | ||
317 | .name = "s5p-hdmiphy", | ||
318 | }, | ||
319 | .probe = hdmiphy_probe, | ||
320 | .remove = hdmiphy_remove, | ||
321 | .id_table = hdmiphy_id, | ||
322 | }; | ||
323 | |||
324 | module_i2c_driver(hdmiphy_driver); | ||
diff --git a/drivers/media/platform/s5p-tv/mixer.h b/drivers/media/platform/s5p-tv/mixer.h deleted file mode 100644 index 869f0ce86f6e..000000000000 --- a/drivers/media/platform/s5p-tv/mixer.h +++ /dev/null | |||
@@ -1,364 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung TV Mixer driver | ||
3 | * | ||
4 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
5 | * | ||
6 | * Tomasz Stanislawski, <t.stanislaws@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 as published | ||
10 | * by the Free Software Foundiation. either version 2 of the License, | ||
11 | * or (at your option) any later version | ||
12 | */ | ||
13 | |||
14 | #ifndef SAMSUNG_MIXER_H | ||
15 | #define SAMSUNG_MIXER_H | ||
16 | |||
17 | #ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG | ||
18 | #define DEBUG | ||
19 | #endif | ||
20 | |||
21 | #include <linux/fb.h> | ||
22 | #include <linux/irqreturn.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <linux/wait.h> | ||
26 | #include <media/v4l2-device.h> | ||
27 | #include <media/videobuf2-v4l2.h> | ||
28 | |||
29 | #include "regs-mixer.h" | ||
30 | |||
31 | /** maximum number of output interfaces */ | ||
32 | #define MXR_MAX_OUTPUTS 2 | ||
33 | /** maximum number of input interfaces (layers) */ | ||
34 | #define MXR_MAX_LAYERS 3 | ||
35 | #define MXR_DRIVER_NAME "s5p-mixer" | ||
36 | /** maximal number of planes for every layer */ | ||
37 | #define MXR_MAX_PLANES 2 | ||
38 | |||
39 | #define MXR_ENABLE 1 | ||
40 | #define MXR_DISABLE 0 | ||
41 | |||
42 | /** description of a macroblock for packed formats */ | ||
43 | struct mxr_block { | ||
44 | /** vertical number of pixels in macroblock */ | ||
45 | unsigned int width; | ||
46 | /** horizontal number of pixels in macroblock */ | ||
47 | unsigned int height; | ||
48 | /** size of block in bytes */ | ||
49 | unsigned int size; | ||
50 | }; | ||
51 | |||
52 | /** description of supported format */ | ||
53 | struct mxr_format { | ||
54 | /** format name/mnemonic */ | ||
55 | const char *name; | ||
56 | /** fourcc identifier */ | ||
57 | u32 fourcc; | ||
58 | /** colorspace identifier */ | ||
59 | enum v4l2_colorspace colorspace; | ||
60 | /** number of planes in image data */ | ||
61 | int num_planes; | ||
62 | /** description of block for each plane */ | ||
63 | struct mxr_block plane[MXR_MAX_PLANES]; | ||
64 | /** number of subframes in image data */ | ||
65 | int num_subframes; | ||
66 | /** specifies to which subframe belong given plane */ | ||
67 | int plane2subframe[MXR_MAX_PLANES]; | ||
68 | /** internal code, driver dependent */ | ||
69 | unsigned long cookie; | ||
70 | }; | ||
71 | |||
72 | /** description of crop configuration for image */ | ||
73 | struct mxr_crop { | ||
74 | /** width of layer in pixels */ | ||
75 | unsigned int full_width; | ||
76 | /** height of layer in pixels */ | ||
77 | unsigned int full_height; | ||
78 | /** horizontal offset of first pixel to be displayed */ | ||
79 | unsigned int x_offset; | ||
80 | /** vertical offset of first pixel to be displayed */ | ||
81 | unsigned int y_offset; | ||
82 | /** width of displayed data in pixels */ | ||
83 | unsigned int width; | ||
84 | /** height of displayed data in pixels */ | ||
85 | unsigned int height; | ||
86 | /** indicate which fields are present in buffer */ | ||
87 | unsigned int field; | ||
88 | }; | ||
89 | |||
90 | /** stages of geometry operations */ | ||
91 | enum mxr_geometry_stage { | ||
92 | MXR_GEOMETRY_SINK, | ||
93 | MXR_GEOMETRY_COMPOSE, | ||
94 | MXR_GEOMETRY_CROP, | ||
95 | MXR_GEOMETRY_SOURCE, | ||
96 | }; | ||
97 | |||
98 | /* flag indicating that offset should be 0 */ | ||
99 | #define MXR_NO_OFFSET 0x80000000 | ||
100 | |||
101 | /** description of transformation from source to destination image */ | ||
102 | struct mxr_geometry { | ||
103 | /** cropping for source image */ | ||
104 | struct mxr_crop src; | ||
105 | /** cropping for destination image */ | ||
106 | struct mxr_crop dst; | ||
107 | /** layer-dependant description of horizontal scaling */ | ||
108 | unsigned int x_ratio; | ||
109 | /** layer-dependant description of vertical scaling */ | ||
110 | unsigned int y_ratio; | ||
111 | }; | ||
112 | |||
113 | /** instance of a buffer */ | ||
114 | struct mxr_buffer { | ||
115 | /** common v4l buffer stuff -- must be first */ | ||
116 | struct vb2_v4l2_buffer vb; | ||
117 | /** node for layer's lists */ | ||
118 | struct list_head list; | ||
119 | }; | ||
120 | |||
121 | |||
122 | /** internal states of layer */ | ||
123 | enum mxr_layer_state { | ||
124 | /** layers is not shown */ | ||
125 | MXR_LAYER_IDLE = 0, | ||
126 | /** layer is shown */ | ||
127 | MXR_LAYER_STREAMING, | ||
128 | /** state before STREAMOFF is finished */ | ||
129 | MXR_LAYER_STREAMING_FINISH, | ||
130 | }; | ||
131 | |||
132 | /** forward declarations */ | ||
133 | struct mxr_device; | ||
134 | struct mxr_layer; | ||
135 | |||
136 | /** callback for layers operation */ | ||
137 | struct mxr_layer_ops { | ||
138 | /* TODO: try to port it to subdev API */ | ||
139 | /** handler for resource release function */ | ||
140 | void (*release)(struct mxr_layer *); | ||
141 | /** setting buffer to HW */ | ||
142 | void (*buffer_set)(struct mxr_layer *, struct mxr_buffer *); | ||
143 | /** setting format and geometry in HW */ | ||
144 | void (*format_set)(struct mxr_layer *); | ||
145 | /** streaming stop/start */ | ||
146 | void (*stream_set)(struct mxr_layer *, int); | ||
147 | /** adjusting geometry */ | ||
148 | void (*fix_geometry)(struct mxr_layer *, | ||
149 | enum mxr_geometry_stage, unsigned long); | ||
150 | }; | ||
151 | |||
152 | /** layer instance, a single window and content displayed on output */ | ||
153 | struct mxr_layer { | ||
154 | /** parent mixer device */ | ||
155 | struct mxr_device *mdev; | ||
156 | /** layer index (unique identifier) */ | ||
157 | int idx; | ||
158 | /** callbacks for layer methods */ | ||
159 | struct mxr_layer_ops ops; | ||
160 | /** format array */ | ||
161 | const struct mxr_format **fmt_array; | ||
162 | /** size of format array */ | ||
163 | unsigned long fmt_array_size; | ||
164 | |||
165 | /** lock for protection of list and state fields */ | ||
166 | spinlock_t enq_slock; | ||
167 | /** list for enqueued buffers */ | ||
168 | struct list_head enq_list; | ||
169 | /** buffer currently owned by hardware in temporary registers */ | ||
170 | struct mxr_buffer *update_buf; | ||
171 | /** buffer currently owned by hardware in shadow registers */ | ||
172 | struct mxr_buffer *shadow_buf; | ||
173 | /** state of layer IDLE/STREAMING */ | ||
174 | enum mxr_layer_state state; | ||
175 | |||
176 | /** mutex for protection of fields below */ | ||
177 | struct mutex mutex; | ||
178 | /** handler for video node */ | ||
179 | struct video_device vfd; | ||
180 | /** queue for output buffers */ | ||
181 | struct vb2_queue vb_queue; | ||
182 | /** current image format */ | ||
183 | const struct mxr_format *fmt; | ||
184 | /** current geometry of image */ | ||
185 | struct mxr_geometry geo; | ||
186 | }; | ||
187 | |||
188 | /** description of mixers output interface */ | ||
189 | struct mxr_output { | ||
190 | /** name of output */ | ||
191 | char name[32]; | ||
192 | /** output subdev */ | ||
193 | struct v4l2_subdev *sd; | ||
194 | /** cookie used for configuration of registers */ | ||
195 | int cookie; | ||
196 | }; | ||
197 | |||
198 | /** specify source of output subdevs */ | ||
199 | struct mxr_output_conf { | ||
200 | /** name of output (connector) */ | ||
201 | char *output_name; | ||
202 | /** name of module that generates output subdev */ | ||
203 | char *module_name; | ||
204 | /** cookie need for mixer HW */ | ||
205 | int cookie; | ||
206 | }; | ||
207 | |||
208 | struct clk; | ||
209 | struct regulator; | ||
210 | |||
211 | /** auxiliary resources used my mixer */ | ||
212 | struct mxr_resources { | ||
213 | /** interrupt index */ | ||
214 | int irq; | ||
215 | /** pointer to Mixer registers */ | ||
216 | void __iomem *mxr_regs; | ||
217 | /** pointer to Video Processor registers */ | ||
218 | void __iomem *vp_regs; | ||
219 | /** other resources, should used under mxr_device.mutex */ | ||
220 | struct clk *mixer; | ||
221 | struct clk *vp; | ||
222 | struct clk *sclk_mixer; | ||
223 | struct clk *sclk_hdmi; | ||
224 | struct clk *sclk_dac; | ||
225 | }; | ||
226 | |||
227 | /* event flags used */ | ||
228 | enum mxr_devide_flags { | ||
229 | MXR_EVENT_VSYNC = 0, | ||
230 | MXR_EVENT_TOP = 1, | ||
231 | }; | ||
232 | |||
233 | /** drivers instance */ | ||
234 | struct mxr_device { | ||
235 | /** master device */ | ||
236 | struct device *dev; | ||
237 | /** state of each layer */ | ||
238 | struct mxr_layer *layer[MXR_MAX_LAYERS]; | ||
239 | /** state of each output */ | ||
240 | struct mxr_output *output[MXR_MAX_OUTPUTS]; | ||
241 | /** number of registered outputs */ | ||
242 | int output_cnt; | ||
243 | |||
244 | /* video resources */ | ||
245 | |||
246 | /** V4L2 device */ | ||
247 | struct v4l2_device v4l2_dev; | ||
248 | /** event wait queue */ | ||
249 | wait_queue_head_t event_queue; | ||
250 | /** state flags */ | ||
251 | unsigned long event_flags; | ||
252 | |||
253 | /** spinlock for protection of registers */ | ||
254 | spinlock_t reg_slock; | ||
255 | |||
256 | /** mutex for protection of fields below */ | ||
257 | struct mutex mutex; | ||
258 | /** number of entities depndant on output configuration */ | ||
259 | int n_output; | ||
260 | /** number of users that do streaming */ | ||
261 | int n_streamer; | ||
262 | /** index of current output */ | ||
263 | int current_output; | ||
264 | /** auxiliary resources used my mixer */ | ||
265 | struct mxr_resources res; | ||
266 | }; | ||
267 | |||
268 | /** transform device structure into mixer device */ | ||
269 | static inline struct mxr_device *to_mdev(struct device *dev) | ||
270 | { | ||
271 | struct v4l2_device *vdev = dev_get_drvdata(dev); | ||
272 | return container_of(vdev, struct mxr_device, v4l2_dev); | ||
273 | } | ||
274 | |||
275 | /** get current output data, should be called under mdev's mutex */ | ||
276 | static inline struct mxr_output *to_output(struct mxr_device *mdev) | ||
277 | { | ||
278 | return mdev->output[mdev->current_output]; | ||
279 | } | ||
280 | |||
281 | /** get current output subdev, should be called under mdev's mutex */ | ||
282 | static inline struct v4l2_subdev *to_outsd(struct mxr_device *mdev) | ||
283 | { | ||
284 | struct mxr_output *out = to_output(mdev); | ||
285 | return out ? out->sd : NULL; | ||
286 | } | ||
287 | |||
288 | /** forward declaration for mixer platform data */ | ||
289 | struct mxr_platform_data; | ||
290 | |||
291 | /** acquiring common video resources */ | ||
292 | int mxr_acquire_video(struct mxr_device *mdev, | ||
293 | struct mxr_output_conf *output_cont, int output_count); | ||
294 | |||
295 | /** releasing common video resources */ | ||
296 | void mxr_release_video(struct mxr_device *mdev); | ||
297 | |||
298 | struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx); | ||
299 | struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx); | ||
300 | struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, | ||
301 | int idx, char *name, const struct mxr_layer_ops *ops); | ||
302 | |||
303 | void mxr_base_layer_release(struct mxr_layer *layer); | ||
304 | void mxr_layer_release(struct mxr_layer *layer); | ||
305 | |||
306 | int mxr_base_layer_register(struct mxr_layer *layer); | ||
307 | void mxr_base_layer_unregister(struct mxr_layer *layer); | ||
308 | |||
309 | unsigned long mxr_get_plane_size(const struct mxr_block *blk, | ||
310 | unsigned int width, unsigned int height); | ||
311 | |||
312 | /** adds new consumer for mixer's power */ | ||
313 | int __must_check mxr_power_get(struct mxr_device *mdev); | ||
314 | /** removes consumer for mixer's power */ | ||
315 | void mxr_power_put(struct mxr_device *mdev); | ||
316 | /** add new client for output configuration */ | ||
317 | void mxr_output_get(struct mxr_device *mdev); | ||
318 | /** removes new client for output configuration */ | ||
319 | void mxr_output_put(struct mxr_device *mdev); | ||
320 | /** add new client for streaming */ | ||
321 | void mxr_streamer_get(struct mxr_device *mdev); | ||
322 | /** removes new client for streaming */ | ||
323 | void mxr_streamer_put(struct mxr_device *mdev); | ||
324 | /** returns format of data delivared to current output */ | ||
325 | void mxr_get_mbus_fmt(struct mxr_device *mdev, | ||
326 | struct v4l2_mbus_framefmt *mbus_fmt); | ||
327 | |||
328 | /* Debug */ | ||
329 | |||
330 | #define mxr_err(mdev, fmt, ...) dev_err(mdev->dev, fmt, ##__VA_ARGS__) | ||
331 | #define mxr_warn(mdev, fmt, ...) dev_warn(mdev->dev, fmt, ##__VA_ARGS__) | ||
332 | #define mxr_info(mdev, fmt, ...) dev_info(mdev->dev, fmt, ##__VA_ARGS__) | ||
333 | |||
334 | #ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG | ||
335 | #define mxr_dbg(mdev, fmt, ...) dev_dbg(mdev->dev, fmt, ##__VA_ARGS__) | ||
336 | #else | ||
337 | #define mxr_dbg(mdev, fmt, ...) do { (void) mdev; } while (0) | ||
338 | #endif | ||
339 | |||
340 | /* accessing Mixer's and Video Processor's registers */ | ||
341 | |||
342 | void mxr_vsync_set_update(struct mxr_device *mdev, int en); | ||
343 | void mxr_reg_reset(struct mxr_device *mdev); | ||
344 | irqreturn_t mxr_irq_handler(int irq, void *dev_data); | ||
345 | void mxr_reg_s_output(struct mxr_device *mdev, int cookie); | ||
346 | void mxr_reg_streamon(struct mxr_device *mdev); | ||
347 | void mxr_reg_streamoff(struct mxr_device *mdev); | ||
348 | int mxr_reg_wait4vsync(struct mxr_device *mdev); | ||
349 | void mxr_reg_set_mbus_fmt(struct mxr_device *mdev, | ||
350 | struct v4l2_mbus_framefmt *fmt); | ||
351 | void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en); | ||
352 | void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr); | ||
353 | void mxr_reg_graph_format(struct mxr_device *mdev, int idx, | ||
354 | const struct mxr_format *fmt, const struct mxr_geometry *geo); | ||
355 | |||
356 | void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en); | ||
357 | void mxr_reg_vp_buffer(struct mxr_device *mdev, | ||
358 | dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2]); | ||
359 | void mxr_reg_vp_format(struct mxr_device *mdev, | ||
360 | const struct mxr_format *fmt, const struct mxr_geometry *geo); | ||
361 | void mxr_reg_dump(struct mxr_device *mdev); | ||
362 | |||
363 | #endif /* SAMSUNG_MIXER_H */ | ||
364 | |||
diff --git a/drivers/media/platform/s5p-tv/mixer_drv.c b/drivers/media/platform/s5p-tv/mixer_drv.c deleted file mode 100644 index 8a5d19469ddc..000000000000 --- a/drivers/media/platform/s5p-tv/mixer_drv.c +++ /dev/null | |||
@@ -1,527 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung TV Mixer driver | ||
3 | * | ||
4 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
5 | * | ||
6 | * Tomasz Stanislawski, <t.stanislaws@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 as published | ||
10 | * by the Free Software Foundiation. either version 2 of the License, | ||
11 | * or (at your option) any later version | ||
12 | */ | ||
13 | |||
14 | #include "mixer.h" | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <linux/fb.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/pm_runtime.h> | ||
24 | #include <linux/clk.h> | ||
25 | |||
26 | MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>"); | ||
27 | MODULE_DESCRIPTION("Samsung MIXER"); | ||
28 | MODULE_LICENSE("GPL"); | ||
29 | |||
30 | /* --------- DRIVER PARAMETERS ---------- */ | ||
31 | |||
32 | static struct mxr_output_conf mxr_output_conf[] = { | ||
33 | { | ||
34 | .output_name = "S5P HDMI connector", | ||
35 | .module_name = "s5p-hdmi", | ||
36 | .cookie = 1, | ||
37 | }, | ||
38 | { | ||
39 | .output_name = "S5P SDO connector", | ||
40 | .module_name = "s5p-sdo", | ||
41 | .cookie = 0, | ||
42 | }, | ||
43 | }; | ||
44 | |||
45 | void mxr_get_mbus_fmt(struct mxr_device *mdev, | ||
46 | struct v4l2_mbus_framefmt *mbus_fmt) | ||
47 | { | ||
48 | struct v4l2_subdev *sd; | ||
49 | struct v4l2_subdev_format fmt = { | ||
50 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
51 | }; | ||
52 | int ret; | ||
53 | |||
54 | mutex_lock(&mdev->mutex); | ||
55 | sd = to_outsd(mdev); | ||
56 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | ||
57 | *mbus_fmt = fmt.format; | ||
58 | WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name); | ||
59 | mutex_unlock(&mdev->mutex); | ||
60 | } | ||
61 | |||
62 | void mxr_streamer_get(struct mxr_device *mdev) | ||
63 | { | ||
64 | mutex_lock(&mdev->mutex); | ||
65 | ++mdev->n_streamer; | ||
66 | mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer); | ||
67 | if (mdev->n_streamer == 1) { | ||
68 | struct v4l2_subdev *sd = to_outsd(mdev); | ||
69 | struct v4l2_subdev_format fmt = { | ||
70 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
71 | }; | ||
72 | struct v4l2_mbus_framefmt *mbus_fmt = &fmt.format; | ||
73 | struct mxr_resources *res = &mdev->res; | ||
74 | int ret; | ||
75 | |||
76 | if (to_output(mdev)->cookie == 0) | ||
77 | clk_set_parent(res->sclk_mixer, res->sclk_dac); | ||
78 | else | ||
79 | clk_set_parent(res->sclk_mixer, res->sclk_hdmi); | ||
80 | mxr_reg_s_output(mdev, to_output(mdev)->cookie); | ||
81 | |||
82 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | ||
83 | WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name); | ||
84 | ret = v4l2_subdev_call(sd, video, s_stream, 1); | ||
85 | WARN(ret, "starting stream failed for output %s\n", sd->name); | ||
86 | |||
87 | mxr_reg_set_mbus_fmt(mdev, mbus_fmt); | ||
88 | mxr_reg_streamon(mdev); | ||
89 | ret = mxr_reg_wait4vsync(mdev); | ||
90 | WARN(ret, "failed to get vsync (%d) from output\n", ret); | ||
91 | } | ||
92 | mutex_unlock(&mdev->mutex); | ||
93 | mxr_reg_dump(mdev); | ||
94 | /* FIXME: what to do when streaming fails? */ | ||
95 | } | ||
96 | |||
97 | void mxr_streamer_put(struct mxr_device *mdev) | ||
98 | { | ||
99 | mutex_lock(&mdev->mutex); | ||
100 | --mdev->n_streamer; | ||
101 | mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer); | ||
102 | if (mdev->n_streamer == 0) { | ||
103 | int ret; | ||
104 | struct v4l2_subdev *sd = to_outsd(mdev); | ||
105 | |||
106 | mxr_reg_streamoff(mdev); | ||
107 | /* vsync applies Mixer setup */ | ||
108 | ret = mxr_reg_wait4vsync(mdev); | ||
109 | WARN(ret, "failed to get vsync (%d) from output\n", ret); | ||
110 | ret = v4l2_subdev_call(sd, video, s_stream, 0); | ||
111 | WARN(ret, "stopping stream failed for output %s\n", sd->name); | ||
112 | } | ||
113 | WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n", | ||
114 | mdev->n_streamer); | ||
115 | mutex_unlock(&mdev->mutex); | ||
116 | mxr_reg_dump(mdev); | ||
117 | } | ||
118 | |||
119 | void mxr_output_get(struct mxr_device *mdev) | ||
120 | { | ||
121 | mutex_lock(&mdev->mutex); | ||
122 | ++mdev->n_output; | ||
123 | mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output); | ||
124 | /* turn on auxiliary driver */ | ||
125 | if (mdev->n_output == 1) | ||
126 | v4l2_subdev_call(to_outsd(mdev), core, s_power, 1); | ||
127 | mutex_unlock(&mdev->mutex); | ||
128 | } | ||
129 | |||
130 | void mxr_output_put(struct mxr_device *mdev) | ||
131 | { | ||
132 | mutex_lock(&mdev->mutex); | ||
133 | --mdev->n_output; | ||
134 | mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output); | ||
135 | /* turn on auxiliary driver */ | ||
136 | if (mdev->n_output == 0) | ||
137 | v4l2_subdev_call(to_outsd(mdev), core, s_power, 0); | ||
138 | WARN(mdev->n_output < 0, "negative number of output users (%d)\n", | ||
139 | mdev->n_output); | ||
140 | mutex_unlock(&mdev->mutex); | ||
141 | } | ||
142 | |||
143 | int mxr_power_get(struct mxr_device *mdev) | ||
144 | { | ||
145 | int ret = pm_runtime_get_sync(mdev->dev); | ||
146 | |||
147 | /* returning 1 means that power is already enabled, | ||
148 | * so zero success be returned */ | ||
149 | if (ret < 0) | ||
150 | return ret; | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | void mxr_power_put(struct mxr_device *mdev) | ||
155 | { | ||
156 | pm_runtime_put_sync(mdev->dev); | ||
157 | } | ||
158 | |||
159 | /* --------- RESOURCE MANAGEMENT -------------*/ | ||
160 | |||
161 | static int mxr_acquire_plat_resources(struct mxr_device *mdev, | ||
162 | struct platform_device *pdev) | ||
163 | { | ||
164 | struct resource *res; | ||
165 | int ret; | ||
166 | |||
167 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr"); | ||
168 | if (res == NULL) { | ||
169 | mxr_err(mdev, "get memory resource failed.\n"); | ||
170 | ret = -ENXIO; | ||
171 | goto fail; | ||
172 | } | ||
173 | |||
174 | mdev->res.mxr_regs = ioremap(res->start, resource_size(res)); | ||
175 | if (mdev->res.mxr_regs == NULL) { | ||
176 | mxr_err(mdev, "register mapping failed.\n"); | ||
177 | ret = -ENXIO; | ||
178 | goto fail; | ||
179 | } | ||
180 | |||
181 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp"); | ||
182 | if (res == NULL) { | ||
183 | mxr_err(mdev, "get memory resource failed.\n"); | ||
184 | ret = -ENXIO; | ||
185 | goto fail_mxr_regs; | ||
186 | } | ||
187 | |||
188 | mdev->res.vp_regs = ioremap(res->start, resource_size(res)); | ||
189 | if (mdev->res.vp_regs == NULL) { | ||
190 | mxr_err(mdev, "register mapping failed.\n"); | ||
191 | ret = -ENXIO; | ||
192 | goto fail_mxr_regs; | ||
193 | } | ||
194 | |||
195 | res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq"); | ||
196 | if (res == NULL) { | ||
197 | mxr_err(mdev, "get interrupt resource failed.\n"); | ||
198 | ret = -ENXIO; | ||
199 | goto fail_vp_regs; | ||
200 | } | ||
201 | |||
202 | ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev); | ||
203 | if (ret) { | ||
204 | mxr_err(mdev, "request interrupt failed.\n"); | ||
205 | goto fail_vp_regs; | ||
206 | } | ||
207 | mdev->res.irq = res->start; | ||
208 | |||
209 | return 0; | ||
210 | |||
211 | fail_vp_regs: | ||
212 | iounmap(mdev->res.vp_regs); | ||
213 | |||
214 | fail_mxr_regs: | ||
215 | iounmap(mdev->res.mxr_regs); | ||
216 | |||
217 | fail: | ||
218 | return ret; | ||
219 | } | ||
220 | |||
221 | static void mxr_resource_clear_clocks(struct mxr_resources *res) | ||
222 | { | ||
223 | res->mixer = ERR_PTR(-EINVAL); | ||
224 | res->vp = ERR_PTR(-EINVAL); | ||
225 | res->sclk_mixer = ERR_PTR(-EINVAL); | ||
226 | res->sclk_hdmi = ERR_PTR(-EINVAL); | ||
227 | res->sclk_dac = ERR_PTR(-EINVAL); | ||
228 | } | ||
229 | |||
230 | static void mxr_release_plat_resources(struct mxr_device *mdev) | ||
231 | { | ||
232 | free_irq(mdev->res.irq, mdev); | ||
233 | iounmap(mdev->res.vp_regs); | ||
234 | iounmap(mdev->res.mxr_regs); | ||
235 | } | ||
236 | |||
237 | static void mxr_release_clocks(struct mxr_device *mdev) | ||
238 | { | ||
239 | struct mxr_resources *res = &mdev->res; | ||
240 | |||
241 | if (!IS_ERR(res->sclk_dac)) | ||
242 | clk_put(res->sclk_dac); | ||
243 | if (!IS_ERR(res->sclk_hdmi)) | ||
244 | clk_put(res->sclk_hdmi); | ||
245 | if (!IS_ERR(res->sclk_mixer)) | ||
246 | clk_put(res->sclk_mixer); | ||
247 | if (!IS_ERR(res->vp)) | ||
248 | clk_put(res->vp); | ||
249 | if (!IS_ERR(res->mixer)) | ||
250 | clk_put(res->mixer); | ||
251 | } | ||
252 | |||
253 | static int mxr_acquire_clocks(struct mxr_device *mdev) | ||
254 | { | ||
255 | struct mxr_resources *res = &mdev->res; | ||
256 | struct device *dev = mdev->dev; | ||
257 | |||
258 | mxr_resource_clear_clocks(res); | ||
259 | |||
260 | res->mixer = clk_get(dev, "mixer"); | ||
261 | if (IS_ERR(res->mixer)) { | ||
262 | mxr_err(mdev, "failed to get clock 'mixer'\n"); | ||
263 | goto fail; | ||
264 | } | ||
265 | res->vp = clk_get(dev, "vp"); | ||
266 | if (IS_ERR(res->vp)) { | ||
267 | mxr_err(mdev, "failed to get clock 'vp'\n"); | ||
268 | goto fail; | ||
269 | } | ||
270 | res->sclk_mixer = clk_get(dev, "sclk_mixer"); | ||
271 | if (IS_ERR(res->sclk_mixer)) { | ||
272 | mxr_err(mdev, "failed to get clock 'sclk_mixer'\n"); | ||
273 | goto fail; | ||
274 | } | ||
275 | res->sclk_hdmi = clk_get(dev, "sclk_hdmi"); | ||
276 | if (IS_ERR(res->sclk_hdmi)) { | ||
277 | mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n"); | ||
278 | goto fail; | ||
279 | } | ||
280 | res->sclk_dac = clk_get(dev, "sclk_dac"); | ||
281 | if (IS_ERR(res->sclk_dac)) { | ||
282 | mxr_err(mdev, "failed to get clock 'sclk_dac'\n"); | ||
283 | goto fail; | ||
284 | } | ||
285 | |||
286 | return 0; | ||
287 | fail: | ||
288 | mxr_release_clocks(mdev); | ||
289 | return -ENODEV; | ||
290 | } | ||
291 | |||
292 | static int mxr_acquire_resources(struct mxr_device *mdev, | ||
293 | struct platform_device *pdev) | ||
294 | { | ||
295 | int ret; | ||
296 | ret = mxr_acquire_plat_resources(mdev, pdev); | ||
297 | |||
298 | if (ret) | ||
299 | goto fail; | ||
300 | |||
301 | ret = mxr_acquire_clocks(mdev); | ||
302 | if (ret) | ||
303 | goto fail_plat; | ||
304 | |||
305 | mxr_info(mdev, "resources acquired\n"); | ||
306 | return 0; | ||
307 | |||
308 | fail_plat: | ||
309 | mxr_release_plat_resources(mdev); | ||
310 | fail: | ||
311 | mxr_err(mdev, "resources acquire failed\n"); | ||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | static void mxr_release_resources(struct mxr_device *mdev) | ||
316 | { | ||
317 | mxr_release_clocks(mdev); | ||
318 | mxr_release_plat_resources(mdev); | ||
319 | memset(&mdev->res, 0, sizeof(mdev->res)); | ||
320 | mxr_resource_clear_clocks(&mdev->res); | ||
321 | } | ||
322 | |||
323 | static void mxr_release_layers(struct mxr_device *mdev) | ||
324 | { | ||
325 | int i; | ||
326 | |||
327 | for (i = 0; i < ARRAY_SIZE(mdev->layer); ++i) | ||
328 | if (mdev->layer[i]) | ||
329 | mxr_layer_release(mdev->layer[i]); | ||
330 | } | ||
331 | |||
332 | static int mxr_acquire_layers(struct mxr_device *mdev, | ||
333 | struct mxr_platform_data *pdata) | ||
334 | { | ||
335 | mdev->layer[0] = mxr_graph_layer_create(mdev, 0); | ||
336 | mdev->layer[1] = mxr_graph_layer_create(mdev, 1); | ||
337 | mdev->layer[2] = mxr_vp_layer_create(mdev, 0); | ||
338 | |||
339 | if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) { | ||
340 | mxr_err(mdev, "failed to acquire layers\n"); | ||
341 | goto fail; | ||
342 | } | ||
343 | |||
344 | return 0; | ||
345 | |||
346 | fail: | ||
347 | mxr_release_layers(mdev); | ||
348 | return -ENODEV; | ||
349 | } | ||
350 | |||
351 | /* ---------- POWER MANAGEMENT ----------- */ | ||
352 | |||
353 | static int mxr_runtime_resume(struct device *dev) | ||
354 | { | ||
355 | struct mxr_device *mdev = to_mdev(dev); | ||
356 | struct mxr_resources *res = &mdev->res; | ||
357 | int ret; | ||
358 | |||
359 | mxr_dbg(mdev, "resume - start\n"); | ||
360 | mutex_lock(&mdev->mutex); | ||
361 | /* turn clocks on */ | ||
362 | ret = clk_prepare_enable(res->mixer); | ||
363 | if (ret < 0) { | ||
364 | dev_err(mdev->dev, "clk_prepare_enable(mixer) failed\n"); | ||
365 | goto fail; | ||
366 | } | ||
367 | ret = clk_prepare_enable(res->vp); | ||
368 | if (ret < 0) { | ||
369 | dev_err(mdev->dev, "clk_prepare_enable(vp) failed\n"); | ||
370 | goto fail_mixer; | ||
371 | } | ||
372 | ret = clk_prepare_enable(res->sclk_mixer); | ||
373 | if (ret < 0) { | ||
374 | dev_err(mdev->dev, "clk_prepare_enable(sclk_mixer) failed\n"); | ||
375 | goto fail_vp; | ||
376 | } | ||
377 | /* apply default configuration */ | ||
378 | mxr_reg_reset(mdev); | ||
379 | mxr_dbg(mdev, "resume - finished\n"); | ||
380 | |||
381 | mutex_unlock(&mdev->mutex); | ||
382 | return 0; | ||
383 | |||
384 | fail_vp: | ||
385 | clk_disable_unprepare(res->vp); | ||
386 | fail_mixer: | ||
387 | clk_disable_unprepare(res->mixer); | ||
388 | fail: | ||
389 | mutex_unlock(&mdev->mutex); | ||
390 | dev_err(mdev->dev, "resume failed\n"); | ||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | static int mxr_runtime_suspend(struct device *dev) | ||
395 | { | ||
396 | struct mxr_device *mdev = to_mdev(dev); | ||
397 | struct mxr_resources *res = &mdev->res; | ||
398 | mxr_dbg(mdev, "suspend - start\n"); | ||
399 | mutex_lock(&mdev->mutex); | ||
400 | /* turn clocks off */ | ||
401 | clk_disable_unprepare(res->sclk_mixer); | ||
402 | clk_disable_unprepare(res->vp); | ||
403 | clk_disable_unprepare(res->mixer); | ||
404 | mutex_unlock(&mdev->mutex); | ||
405 | mxr_dbg(mdev, "suspend - finished\n"); | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static const struct dev_pm_ops mxr_pm_ops = { | ||
410 | .runtime_suspend = mxr_runtime_suspend, | ||
411 | .runtime_resume = mxr_runtime_resume, | ||
412 | }; | ||
413 | |||
414 | /* --------- DRIVER INITIALIZATION ---------- */ | ||
415 | |||
416 | static int mxr_probe(struct platform_device *pdev) | ||
417 | { | ||
418 | struct device *dev = &pdev->dev; | ||
419 | struct mxr_platform_data *pdata = dev->platform_data; | ||
420 | struct mxr_device *mdev; | ||
421 | int ret; | ||
422 | |||
423 | /* mdev does not exist yet so no mxr_dbg is used */ | ||
424 | dev_info(dev, "probe start\n"); | ||
425 | |||
426 | mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); | ||
427 | if (!mdev) { | ||
428 | dev_err(dev, "not enough memory.\n"); | ||
429 | ret = -ENOMEM; | ||
430 | goto fail; | ||
431 | } | ||
432 | |||
433 | /* setup pointer to master device */ | ||
434 | mdev->dev = dev; | ||
435 | |||
436 | mutex_init(&mdev->mutex); | ||
437 | spin_lock_init(&mdev->reg_slock); | ||
438 | init_waitqueue_head(&mdev->event_queue); | ||
439 | |||
440 | /* acquire resources: regs, irqs, clocks, regulators */ | ||
441 | ret = mxr_acquire_resources(mdev, pdev); | ||
442 | if (ret) | ||
443 | goto fail_mem; | ||
444 | |||
445 | /* configure resources for video output */ | ||
446 | ret = mxr_acquire_video(mdev, mxr_output_conf, | ||
447 | ARRAY_SIZE(mxr_output_conf)); | ||
448 | if (ret) | ||
449 | goto fail_resources; | ||
450 | |||
451 | /* configure layers */ | ||
452 | ret = mxr_acquire_layers(mdev, pdata); | ||
453 | if (ret) | ||
454 | goto fail_video; | ||
455 | |||
456 | pm_runtime_enable(dev); | ||
457 | |||
458 | mxr_info(mdev, "probe successful\n"); | ||
459 | return 0; | ||
460 | |||
461 | fail_video: | ||
462 | mxr_release_video(mdev); | ||
463 | |||
464 | fail_resources: | ||
465 | mxr_release_resources(mdev); | ||
466 | |||
467 | fail_mem: | ||
468 | kfree(mdev); | ||
469 | |||
470 | fail: | ||
471 | dev_info(dev, "probe failed\n"); | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | static int mxr_remove(struct platform_device *pdev) | ||
476 | { | ||
477 | struct device *dev = &pdev->dev; | ||
478 | struct mxr_device *mdev = to_mdev(dev); | ||
479 | |||
480 | pm_runtime_disable(dev); | ||
481 | |||
482 | mxr_release_layers(mdev); | ||
483 | mxr_release_video(mdev); | ||
484 | mxr_release_resources(mdev); | ||
485 | |||
486 | kfree(mdev); | ||
487 | |||
488 | dev_info(dev, "remove successful\n"); | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static struct platform_driver mxr_driver __refdata = { | ||
493 | .probe = mxr_probe, | ||
494 | .remove = mxr_remove, | ||
495 | .driver = { | ||
496 | .name = MXR_DRIVER_NAME, | ||
497 | .pm = &mxr_pm_ops, | ||
498 | } | ||
499 | }; | ||
500 | |||
501 | static int __init mxr_init(void) | ||
502 | { | ||
503 | int i, ret; | ||
504 | static const char banner[] __initconst = | ||
505 | "Samsung TV Mixer driver, " | ||
506 | "(c) 2010-2011 Samsung Electronics Co., Ltd.\n"; | ||
507 | pr_info("%s\n", banner); | ||
508 | |||
509 | /* Loading auxiliary modules */ | ||
510 | for (i = 0; i < ARRAY_SIZE(mxr_output_conf); ++i) | ||
511 | request_module(mxr_output_conf[i].module_name); | ||
512 | |||
513 | ret = platform_driver_register(&mxr_driver); | ||
514 | if (ret != 0) { | ||
515 | pr_err("s5p-tv: registration of MIXER driver failed\n"); | ||
516 | return -ENXIO; | ||
517 | } | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | module_init(mxr_init); | ||
522 | |||
523 | static void __exit mxr_exit(void) | ||
524 | { | ||
525 | platform_driver_unregister(&mxr_driver); | ||
526 | } | ||
527 | module_exit(mxr_exit); | ||
diff --git a/drivers/media/platform/s5p-tv/mixer_grp_layer.c b/drivers/media/platform/s5p-tv/mixer_grp_layer.c deleted file mode 100644 index d4d2564f7de7..000000000000 --- a/drivers/media/platform/s5p-tv/mixer_grp_layer.c +++ /dev/null | |||
@@ -1,270 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung TV Mixer driver | ||
3 | * | ||
4 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
5 | * | ||
6 | * Tomasz Stanislawski, <t.stanislaws@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 as published | ||
10 | * by the Free Software Foundiation. either version 2 of the License, | ||
11 | * or (at your option) any later version | ||
12 | */ | ||
13 | |||
14 | #include "mixer.h" | ||
15 | |||
16 | #include <media/videobuf2-dma-contig.h> | ||
17 | |||
18 | /* FORMAT DEFINITIONS */ | ||
19 | |||
20 | static const struct mxr_format mxr_fb_fmt_rgb565 = { | ||
21 | .name = "RGB565", | ||
22 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
23 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
24 | .num_planes = 1, | ||
25 | .plane = { | ||
26 | { .width = 1, .height = 1, .size = 2 }, | ||
27 | }, | ||
28 | .num_subframes = 1, | ||
29 | .cookie = 4, | ||
30 | }; | ||
31 | |||
32 | static const struct mxr_format mxr_fb_fmt_argb1555 = { | ||
33 | .name = "ARGB1555", | ||
34 | .num_planes = 1, | ||
35 | .fourcc = V4L2_PIX_FMT_RGB555, | ||
36 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
37 | .plane = { | ||
38 | { .width = 1, .height = 1, .size = 2 }, | ||
39 | }, | ||
40 | .num_subframes = 1, | ||
41 | .cookie = 5, | ||
42 | }; | ||
43 | |||
44 | static const struct mxr_format mxr_fb_fmt_argb4444 = { | ||
45 | .name = "ARGB4444", | ||
46 | .num_planes = 1, | ||
47 | .fourcc = V4L2_PIX_FMT_RGB444, | ||
48 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
49 | .plane = { | ||
50 | { .width = 1, .height = 1, .size = 2 }, | ||
51 | }, | ||
52 | .num_subframes = 1, | ||
53 | .cookie = 6, | ||
54 | }; | ||
55 | |||
56 | static const struct mxr_format mxr_fb_fmt_argb8888 = { | ||
57 | .name = "ARGB8888", | ||
58 | .fourcc = V4L2_PIX_FMT_BGR32, | ||
59 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
60 | .num_planes = 1, | ||
61 | .plane = { | ||
62 | { .width = 1, .height = 1, .size = 4 }, | ||
63 | }, | ||
64 | .num_subframes = 1, | ||
65 | .cookie = 7, | ||
66 | }; | ||
67 | |||
68 | static const struct mxr_format *mxr_graph_format[] = { | ||
69 | &mxr_fb_fmt_rgb565, | ||
70 | &mxr_fb_fmt_argb1555, | ||
71 | &mxr_fb_fmt_argb4444, | ||
72 | &mxr_fb_fmt_argb8888, | ||
73 | }; | ||
74 | |||
75 | /* AUXILIARY CALLBACKS */ | ||
76 | |||
77 | static void mxr_graph_layer_release(struct mxr_layer *layer) | ||
78 | { | ||
79 | mxr_base_layer_unregister(layer); | ||
80 | mxr_base_layer_release(layer); | ||
81 | } | ||
82 | |||
83 | static void mxr_graph_buffer_set(struct mxr_layer *layer, | ||
84 | struct mxr_buffer *buf) | ||
85 | { | ||
86 | dma_addr_t addr = 0; | ||
87 | |||
88 | if (buf) | ||
89 | addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); | ||
90 | mxr_reg_graph_buffer(layer->mdev, layer->idx, addr); | ||
91 | } | ||
92 | |||
93 | static void mxr_graph_stream_set(struct mxr_layer *layer, int en) | ||
94 | { | ||
95 | mxr_reg_graph_layer_stream(layer->mdev, layer->idx, en); | ||
96 | } | ||
97 | |||
98 | static void mxr_graph_format_set(struct mxr_layer *layer) | ||
99 | { | ||
100 | mxr_reg_graph_format(layer->mdev, layer->idx, | ||
101 | layer->fmt, &layer->geo); | ||
102 | } | ||
103 | |||
104 | static inline unsigned int closest(unsigned int x, unsigned int a, | ||
105 | unsigned int b, unsigned long flags) | ||
106 | { | ||
107 | unsigned int mid = (a + b) / 2; | ||
108 | |||
109 | /* choosing closest value with constraints according to table: | ||
110 | * -------------+-----+-----+-----+-------+ | ||
111 | * flags | 0 | LE | GE | LE|GE | | ||
112 | * -------------+-----+-----+-----+-------+ | ||
113 | * x <= a | a | a | a | a | | ||
114 | * a < x <= mid | a | a | b | a | | ||
115 | * mid < x < b | b | a | b | b | | ||
116 | * b <= x | b | b | b | b | | ||
117 | * -------------+-----+-----+-----+-------+ | ||
118 | */ | ||
119 | |||
120 | /* remove all non-constraint flags */ | ||
121 | flags &= V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE; | ||
122 | |||
123 | if (x <= a) | ||
124 | return a; | ||
125 | if (x >= b) | ||
126 | return b; | ||
127 | if (flags == V4L2_SEL_FLAG_LE) | ||
128 | return a; | ||
129 | if (flags == V4L2_SEL_FLAG_GE) | ||
130 | return b; | ||
131 | if (x <= mid) | ||
132 | return a; | ||
133 | return b; | ||
134 | } | ||
135 | |||
136 | static inline unsigned int do_center(unsigned int center, | ||
137 | unsigned int size, unsigned int upper, unsigned int flags) | ||
138 | { | ||
139 | unsigned int lower; | ||
140 | |||
141 | if (flags & MXR_NO_OFFSET) | ||
142 | return 0; | ||
143 | |||
144 | lower = center - min(center, size / 2); | ||
145 | return min(lower, upper - size); | ||
146 | } | ||
147 | |||
148 | static void mxr_graph_fix_geometry(struct mxr_layer *layer, | ||
149 | enum mxr_geometry_stage stage, unsigned long flags) | ||
150 | { | ||
151 | struct mxr_geometry *geo = &layer->geo; | ||
152 | struct mxr_crop *src = &geo->src; | ||
153 | struct mxr_crop *dst = &geo->dst; | ||
154 | unsigned int x_center, y_center; | ||
155 | |||
156 | switch (stage) { | ||
157 | |||
158 | case MXR_GEOMETRY_SINK: /* nothing to be fixed here */ | ||
159 | flags = 0; | ||
160 | /* fall through */ | ||
161 | |||
162 | case MXR_GEOMETRY_COMPOSE: | ||
163 | /* remember center of the area */ | ||
164 | x_center = dst->x_offset + dst->width / 2; | ||
165 | y_center = dst->y_offset + dst->height / 2; | ||
166 | /* round up/down to 2 multiple depending on flags */ | ||
167 | if (flags & V4L2_SEL_FLAG_LE) { | ||
168 | dst->width = round_down(dst->width, 2); | ||
169 | dst->height = round_down(dst->height, 2); | ||
170 | } else { | ||
171 | dst->width = round_up(dst->width, 2); | ||
172 | dst->height = round_up(dst->height, 2); | ||
173 | } | ||
174 | /* assure that compose rect is inside display area */ | ||
175 | dst->width = min(dst->width, dst->full_width); | ||
176 | dst->height = min(dst->height, dst->full_height); | ||
177 | |||
178 | /* ensure that compose is reachable using 2x scaling */ | ||
179 | dst->width = min(dst->width, 2 * src->full_width); | ||
180 | dst->height = min(dst->height, 2 * src->full_height); | ||
181 | |||
182 | /* setup offsets */ | ||
183 | dst->x_offset = do_center(x_center, dst->width, | ||
184 | dst->full_width, flags); | ||
185 | dst->y_offset = do_center(y_center, dst->height, | ||
186 | dst->full_height, flags); | ||
187 | flags = 0; | ||
188 | /* fall through */ | ||
189 | |||
190 | case MXR_GEOMETRY_CROP: | ||
191 | /* remember center of the area */ | ||
192 | x_center = src->x_offset + src->width / 2; | ||
193 | y_center = src->y_offset + src->height / 2; | ||
194 | /* ensure that cropping area lies inside the buffer */ | ||
195 | if (src->full_width < dst->width) | ||
196 | src->width = dst->width / 2; | ||
197 | else | ||
198 | src->width = closest(src->width, dst->width / 2, | ||
199 | dst->width, flags); | ||
200 | |||
201 | if (src->width == dst->width) | ||
202 | geo->x_ratio = 0; | ||
203 | else | ||
204 | geo->x_ratio = 1; | ||
205 | |||
206 | if (src->full_height < dst->height) | ||
207 | src->height = dst->height / 2; | ||
208 | else | ||
209 | src->height = closest(src->height, dst->height / 2, | ||
210 | dst->height, flags); | ||
211 | |||
212 | if (src->height == dst->height) | ||
213 | geo->y_ratio = 0; | ||
214 | else | ||
215 | geo->y_ratio = 1; | ||
216 | |||
217 | /* setup offsets */ | ||
218 | src->x_offset = do_center(x_center, src->width, | ||
219 | src->full_width, flags); | ||
220 | src->y_offset = do_center(y_center, src->height, | ||
221 | src->full_height, flags); | ||
222 | flags = 0; | ||
223 | /* fall through */ | ||
224 | case MXR_GEOMETRY_SOURCE: | ||
225 | src->full_width = clamp_val(src->full_width, | ||
226 | src->width + src->x_offset, 32767); | ||
227 | src->full_height = clamp_val(src->full_height, | ||
228 | src->height + src->y_offset, 2047); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | /* PUBLIC API */ | ||
233 | |||
234 | struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx) | ||
235 | { | ||
236 | struct mxr_layer *layer; | ||
237 | int ret; | ||
238 | const struct mxr_layer_ops ops = { | ||
239 | .release = mxr_graph_layer_release, | ||
240 | .buffer_set = mxr_graph_buffer_set, | ||
241 | .stream_set = mxr_graph_stream_set, | ||
242 | .format_set = mxr_graph_format_set, | ||
243 | .fix_geometry = mxr_graph_fix_geometry, | ||
244 | }; | ||
245 | char name[32]; | ||
246 | |||
247 | sprintf(name, "graph%d", idx); | ||
248 | |||
249 | layer = mxr_base_layer_create(mdev, idx, name, &ops); | ||
250 | if (layer == NULL) { | ||
251 | mxr_err(mdev, "failed to initialize layer(%d) base\n", idx); | ||
252 | goto fail; | ||
253 | } | ||
254 | |||
255 | layer->fmt_array = mxr_graph_format; | ||
256 | layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format); | ||
257 | |||
258 | ret = mxr_base_layer_register(layer); | ||
259 | if (ret) | ||
260 | goto fail_layer; | ||
261 | |||
262 | return layer; | ||
263 | |||
264 | fail_layer: | ||
265 | mxr_base_layer_release(layer); | ||
266 | |||
267 | fail: | ||
268 | return NULL; | ||
269 | } | ||
270 | |||
diff --git a/drivers/media/platform/s5p-tv/mixer_reg.c b/drivers/media/platform/s5p-tv/mixer_reg.c deleted file mode 100644 index a0ec14a1da13..000000000000 --- a/drivers/media/platform/s5p-tv/mixer_reg.c +++ /dev/null | |||
@@ -1,551 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung TV Mixer driver | ||
3 | * | ||
4 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
5 | * | ||
6 | * Tomasz Stanislawski, <t.stanislaws@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 as published | ||
10 | * by the Free Software Foundiation. either version 2 of the License, | ||
11 | * or (at your option) any later version | ||
12 | */ | ||
13 | |||
14 | #include "mixer.h" | ||
15 | #include "regs-mixer.h" | ||
16 | #include "regs-vp.h" | ||
17 | |||
18 | #include <linux/delay.h> | ||
19 | |||
20 | /* Register access subroutines */ | ||
21 | |||
22 | static inline u32 vp_read(struct mxr_device *mdev, u32 reg_id) | ||
23 | { | ||
24 | return readl(mdev->res.vp_regs + reg_id); | ||
25 | } | ||
26 | |||
27 | static inline void vp_write(struct mxr_device *mdev, u32 reg_id, u32 val) | ||
28 | { | ||
29 | writel(val, mdev->res.vp_regs + reg_id); | ||
30 | } | ||
31 | |||
32 | static inline void vp_write_mask(struct mxr_device *mdev, u32 reg_id, | ||
33 | u32 val, u32 mask) | ||
34 | { | ||
35 | u32 old = vp_read(mdev, reg_id); | ||
36 | |||
37 | val = (val & mask) | (old & ~mask); | ||
38 | writel(val, mdev->res.vp_regs + reg_id); | ||
39 | } | ||
40 | |||
41 | static inline u32 mxr_read(struct mxr_device *mdev, u32 reg_id) | ||
42 | { | ||
43 | return readl(mdev->res.mxr_regs + reg_id); | ||
44 | } | ||
45 | |||
46 | static inline void mxr_write(struct mxr_device *mdev, u32 reg_id, u32 val) | ||
47 | { | ||
48 | writel(val, mdev->res.mxr_regs + reg_id); | ||
49 | } | ||
50 | |||
51 | static inline void mxr_write_mask(struct mxr_device *mdev, u32 reg_id, | ||
52 | u32 val, u32 mask) | ||
53 | { | ||
54 | u32 old = mxr_read(mdev, reg_id); | ||
55 | |||
56 | val = (val & mask) | (old & ~mask); | ||
57 | writel(val, mdev->res.mxr_regs + reg_id); | ||
58 | } | ||
59 | |||
60 | void mxr_vsync_set_update(struct mxr_device *mdev, int en) | ||
61 | { | ||
62 | /* block update on vsync */ | ||
63 | mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_SYNC_ENABLE : 0, | ||
64 | MXR_STATUS_SYNC_ENABLE); | ||
65 | vp_write(mdev, VP_SHADOW_UPDATE, en ? VP_SHADOW_UPDATE_ENABLE : 0); | ||
66 | } | ||
67 | |||
68 | static void __mxr_reg_vp_reset(struct mxr_device *mdev) | ||
69 | { | ||
70 | int tries = 100; | ||
71 | |||
72 | vp_write(mdev, VP_SRESET, VP_SRESET_PROCESSING); | ||
73 | for (tries = 100; tries; --tries) { | ||
74 | /* waiting until VP_SRESET_PROCESSING is 0 */ | ||
75 | if (~vp_read(mdev, VP_SRESET) & VP_SRESET_PROCESSING) | ||
76 | break; | ||
77 | mdelay(10); | ||
78 | } | ||
79 | WARN(tries == 0, "failed to reset Video Processor\n"); | ||
80 | } | ||
81 | |||
82 | static void mxr_reg_vp_default_filter(struct mxr_device *mdev); | ||
83 | |||
84 | void mxr_reg_reset(struct mxr_device *mdev) | ||
85 | { | ||
86 | unsigned long flags; | ||
87 | u32 val; /* value stored to register */ | ||
88 | |||
89 | spin_lock_irqsave(&mdev->reg_slock, flags); | ||
90 | mxr_vsync_set_update(mdev, MXR_DISABLE); | ||
91 | |||
92 | /* set output in RGB888 mode */ | ||
93 | mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_RGB888); | ||
94 | |||
95 | /* 16 beat burst in DMA */ | ||
96 | mxr_write_mask(mdev, MXR_STATUS, MXR_STATUS_16_BURST, | ||
97 | MXR_STATUS_BURST_MASK); | ||
98 | |||
99 | /* setting default layer priority: layer1 > video > layer0 | ||
100 | * because typical usage scenario would be | ||
101 | * layer0 - framebuffer | ||
102 | * video - video overlay | ||
103 | * layer1 - OSD | ||
104 | */ | ||
105 | val = MXR_LAYER_CFG_GRP0_VAL(1); | ||
106 | val |= MXR_LAYER_CFG_VP_VAL(2); | ||
107 | val |= MXR_LAYER_CFG_GRP1_VAL(3); | ||
108 | mxr_write(mdev, MXR_LAYER_CFG, val); | ||
109 | |||
110 | /* use dark gray background color */ | ||
111 | mxr_write(mdev, MXR_BG_COLOR0, 0x808080); | ||
112 | mxr_write(mdev, MXR_BG_COLOR1, 0x808080); | ||
113 | mxr_write(mdev, MXR_BG_COLOR2, 0x808080); | ||
114 | |||
115 | /* setting graphical layers */ | ||
116 | |||
117 | val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */ | ||
118 | val |= MXR_GRP_CFG_BLEND_PRE_MUL; /* premul mode */ | ||
119 | val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */ | ||
120 | |||
121 | /* the same configuration for both layers */ | ||
122 | mxr_write(mdev, MXR_GRAPHIC_CFG(0), val); | ||
123 | mxr_write(mdev, MXR_GRAPHIC_CFG(1), val); | ||
124 | |||
125 | /* configuration of Video Processor Registers */ | ||
126 | __mxr_reg_vp_reset(mdev); | ||
127 | mxr_reg_vp_default_filter(mdev); | ||
128 | |||
129 | /* enable all interrupts */ | ||
130 | mxr_write_mask(mdev, MXR_INT_EN, ~0, MXR_INT_EN_ALL); | ||
131 | |||
132 | mxr_vsync_set_update(mdev, MXR_ENABLE); | ||
133 | spin_unlock_irqrestore(&mdev->reg_slock, flags); | ||
134 | } | ||
135 | |||
136 | void mxr_reg_graph_format(struct mxr_device *mdev, int idx, | ||
137 | const struct mxr_format *fmt, const struct mxr_geometry *geo) | ||
138 | { | ||
139 | u32 val; | ||
140 | unsigned long flags; | ||
141 | |||
142 | spin_lock_irqsave(&mdev->reg_slock, flags); | ||
143 | mxr_vsync_set_update(mdev, MXR_DISABLE); | ||
144 | |||
145 | /* setup format */ | ||
146 | mxr_write_mask(mdev, MXR_GRAPHIC_CFG(idx), | ||
147 | MXR_GRP_CFG_FORMAT_VAL(fmt->cookie), MXR_GRP_CFG_FORMAT_MASK); | ||
148 | |||
149 | /* setup geometry */ | ||
150 | mxr_write(mdev, MXR_GRAPHIC_SPAN(idx), geo->src.full_width); | ||
151 | val = MXR_GRP_WH_WIDTH(geo->src.width); | ||
152 | val |= MXR_GRP_WH_HEIGHT(geo->src.height); | ||
153 | val |= MXR_GRP_WH_H_SCALE(geo->x_ratio); | ||
154 | val |= MXR_GRP_WH_V_SCALE(geo->y_ratio); | ||
155 | mxr_write(mdev, MXR_GRAPHIC_WH(idx), val); | ||
156 | |||
157 | /* setup offsets in source image */ | ||
158 | val = MXR_GRP_SXY_SX(geo->src.x_offset); | ||
159 | val |= MXR_GRP_SXY_SY(geo->src.y_offset); | ||
160 | mxr_write(mdev, MXR_GRAPHIC_SXY(idx), val); | ||
161 | |||
162 | /* setup offsets in display image */ | ||
163 | val = MXR_GRP_DXY_DX(geo->dst.x_offset); | ||
164 | val |= MXR_GRP_DXY_DY(geo->dst.y_offset); | ||
165 | mxr_write(mdev, MXR_GRAPHIC_DXY(idx), val); | ||
166 | |||
167 | mxr_vsync_set_update(mdev, MXR_ENABLE); | ||
168 | spin_unlock_irqrestore(&mdev->reg_slock, flags); | ||
169 | } | ||
170 | |||
171 | void mxr_reg_vp_format(struct mxr_device *mdev, | ||
172 | const struct mxr_format *fmt, const struct mxr_geometry *geo) | ||
173 | { | ||
174 | unsigned long flags; | ||
175 | |||
176 | spin_lock_irqsave(&mdev->reg_slock, flags); | ||
177 | mxr_vsync_set_update(mdev, MXR_DISABLE); | ||
178 | |||
179 | vp_write_mask(mdev, VP_MODE, fmt->cookie, VP_MODE_FMT_MASK); | ||
180 | |||
181 | /* setting size of input image */ | ||
182 | vp_write(mdev, VP_IMG_SIZE_Y, VP_IMG_HSIZE(geo->src.full_width) | | ||
183 | VP_IMG_VSIZE(geo->src.full_height)); | ||
184 | /* chroma height has to reduced by 2 to avoid chroma distorions */ | ||
185 | vp_write(mdev, VP_IMG_SIZE_C, VP_IMG_HSIZE(geo->src.full_width) | | ||
186 | VP_IMG_VSIZE(geo->src.full_height / 2)); | ||
187 | |||
188 | vp_write(mdev, VP_SRC_WIDTH, geo->src.width); | ||
189 | vp_write(mdev, VP_SRC_HEIGHT, geo->src.height); | ||
190 | vp_write(mdev, VP_SRC_H_POSITION, | ||
191 | VP_SRC_H_POSITION_VAL(geo->src.x_offset)); | ||
192 | vp_write(mdev, VP_SRC_V_POSITION, geo->src.y_offset); | ||
193 | |||
194 | vp_write(mdev, VP_DST_WIDTH, geo->dst.width); | ||
195 | vp_write(mdev, VP_DST_H_POSITION, geo->dst.x_offset); | ||
196 | if (geo->dst.field == V4L2_FIELD_INTERLACED) { | ||
197 | vp_write(mdev, VP_DST_HEIGHT, geo->dst.height / 2); | ||
198 | vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset / 2); | ||
199 | } else { | ||
200 | vp_write(mdev, VP_DST_HEIGHT, geo->dst.height); | ||
201 | vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset); | ||
202 | } | ||
203 | |||
204 | vp_write(mdev, VP_H_RATIO, geo->x_ratio); | ||
205 | vp_write(mdev, VP_V_RATIO, geo->y_ratio); | ||
206 | |||
207 | vp_write(mdev, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE); | ||
208 | |||
209 | mxr_vsync_set_update(mdev, MXR_ENABLE); | ||
210 | spin_unlock_irqrestore(&mdev->reg_slock, flags); | ||
211 | |||
212 | } | ||
213 | |||
214 | void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr) | ||
215 | { | ||
216 | u32 val = addr ? ~0 : 0; | ||
217 | unsigned long flags; | ||
218 | |||
219 | spin_lock_irqsave(&mdev->reg_slock, flags); | ||
220 | mxr_vsync_set_update(mdev, MXR_DISABLE); | ||
221 | |||
222 | if (idx == 0) | ||
223 | mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP0_ENABLE); | ||
224 | else | ||
225 | mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP1_ENABLE); | ||
226 | mxr_write(mdev, MXR_GRAPHIC_BASE(idx), addr); | ||
227 | |||
228 | mxr_vsync_set_update(mdev, MXR_ENABLE); | ||
229 | spin_unlock_irqrestore(&mdev->reg_slock, flags); | ||
230 | } | ||
231 | |||
232 | void mxr_reg_vp_buffer(struct mxr_device *mdev, | ||
233 | dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2]) | ||
234 | { | ||
235 | u32 val = luma_addr[0] ? ~0 : 0; | ||
236 | unsigned long flags; | ||
237 | |||
238 | spin_lock_irqsave(&mdev->reg_slock, flags); | ||
239 | mxr_vsync_set_update(mdev, MXR_DISABLE); | ||
240 | |||
241 | mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_VP_ENABLE); | ||
242 | vp_write_mask(mdev, VP_ENABLE, val, VP_ENABLE_ON); | ||
243 | /* TODO: fix tiled mode */ | ||
244 | vp_write(mdev, VP_TOP_Y_PTR, luma_addr[0]); | ||
245 | vp_write(mdev, VP_TOP_C_PTR, chroma_addr[0]); | ||
246 | vp_write(mdev, VP_BOT_Y_PTR, luma_addr[1]); | ||
247 | vp_write(mdev, VP_BOT_C_PTR, chroma_addr[1]); | ||
248 | |||
249 | mxr_vsync_set_update(mdev, MXR_ENABLE); | ||
250 | spin_unlock_irqrestore(&mdev->reg_slock, flags); | ||
251 | } | ||
252 | |||
253 | static void mxr_irq_layer_handle(struct mxr_layer *layer) | ||
254 | { | ||
255 | struct list_head *head = &layer->enq_list; | ||
256 | struct mxr_buffer *done; | ||
257 | |||
258 | /* skip non-existing layer */ | ||
259 | if (layer == NULL) | ||
260 | return; | ||
261 | |||
262 | spin_lock(&layer->enq_slock); | ||
263 | if (layer->state == MXR_LAYER_IDLE) | ||
264 | goto done; | ||
265 | |||
266 | done = layer->shadow_buf; | ||
267 | layer->shadow_buf = layer->update_buf; | ||
268 | |||
269 | if (list_empty(head)) { | ||
270 | if (layer->state != MXR_LAYER_STREAMING) | ||
271 | layer->update_buf = NULL; | ||
272 | } else { | ||
273 | struct mxr_buffer *next; | ||
274 | next = list_first_entry(head, struct mxr_buffer, list); | ||
275 | list_del(&next->list); | ||
276 | layer->update_buf = next; | ||
277 | } | ||
278 | |||
279 | layer->ops.buffer_set(layer, layer->update_buf); | ||
280 | |||
281 | if (done && done != layer->shadow_buf) | ||
282 | vb2_buffer_done(&done->vb.vb2_buf, VB2_BUF_STATE_DONE); | ||
283 | |||
284 | done: | ||
285 | spin_unlock(&layer->enq_slock); | ||
286 | } | ||
287 | |||
288 | irqreturn_t mxr_irq_handler(int irq, void *dev_data) | ||
289 | { | ||
290 | struct mxr_device *mdev = dev_data; | ||
291 | u32 i, val; | ||
292 | |||
293 | spin_lock(&mdev->reg_slock); | ||
294 | val = mxr_read(mdev, MXR_INT_STATUS); | ||
295 | |||
296 | /* wake up process waiting for VSYNC */ | ||
297 | if (val & MXR_INT_STATUS_VSYNC) { | ||
298 | set_bit(MXR_EVENT_VSYNC, &mdev->event_flags); | ||
299 | /* toggle TOP field event if working in interlaced mode */ | ||
300 | if (~mxr_read(mdev, MXR_CFG) & MXR_CFG_SCAN_PROGRASSIVE) | ||
301 | change_bit(MXR_EVENT_TOP, &mdev->event_flags); | ||
302 | wake_up(&mdev->event_queue); | ||
303 | /* vsync interrupt use different bit for read and clear */ | ||
304 | val &= ~MXR_INT_STATUS_VSYNC; | ||
305 | val |= MXR_INT_CLEAR_VSYNC; | ||
306 | } | ||
307 | |||
308 | /* clear interrupts */ | ||
309 | mxr_write(mdev, MXR_INT_STATUS, val); | ||
310 | |||
311 | spin_unlock(&mdev->reg_slock); | ||
312 | /* leave on non-vsync event */ | ||
313 | if (~val & MXR_INT_CLEAR_VSYNC) | ||
314 | return IRQ_HANDLED; | ||
315 | /* skip layer update on bottom field */ | ||
316 | if (!test_bit(MXR_EVENT_TOP, &mdev->event_flags)) | ||
317 | return IRQ_HANDLED; | ||
318 | for (i = 0; i < MXR_MAX_LAYERS; ++i) | ||
319 | mxr_irq_layer_handle(mdev->layer[i]); | ||
320 | return IRQ_HANDLED; | ||
321 | } | ||
322 | |||
323 | void mxr_reg_s_output(struct mxr_device *mdev, int cookie) | ||
324 | { | ||
325 | u32 val; | ||
326 | |||
327 | val = cookie == 0 ? MXR_CFG_DST_SDO : MXR_CFG_DST_HDMI; | ||
328 | mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_DST_MASK); | ||
329 | } | ||
330 | |||
331 | void mxr_reg_streamon(struct mxr_device *mdev) | ||
332 | { | ||
333 | unsigned long flags; | ||
334 | |||
335 | spin_lock_irqsave(&mdev->reg_slock, flags); | ||
336 | /* single write -> no need to block vsync update */ | ||
337 | |||
338 | /* start MIXER */ | ||
339 | mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN); | ||
340 | set_bit(MXR_EVENT_TOP, &mdev->event_flags); | ||
341 | |||
342 | spin_unlock_irqrestore(&mdev->reg_slock, flags); | ||
343 | } | ||
344 | |||
345 | void mxr_reg_streamoff(struct mxr_device *mdev) | ||
346 | { | ||
347 | unsigned long flags; | ||
348 | |||
349 | spin_lock_irqsave(&mdev->reg_slock, flags); | ||
350 | /* single write -> no need to block vsync update */ | ||
351 | |||
352 | /* stop MIXER */ | ||
353 | mxr_write_mask(mdev, MXR_STATUS, 0, MXR_STATUS_REG_RUN); | ||
354 | |||
355 | spin_unlock_irqrestore(&mdev->reg_slock, flags); | ||
356 | } | ||
357 | |||
358 | int mxr_reg_wait4vsync(struct mxr_device *mdev) | ||
359 | { | ||
360 | long time_left; | ||
361 | |||
362 | clear_bit(MXR_EVENT_VSYNC, &mdev->event_flags); | ||
363 | /* TODO: consider adding interruptible */ | ||
364 | time_left = wait_event_timeout(mdev->event_queue, | ||
365 | test_bit(MXR_EVENT_VSYNC, &mdev->event_flags), | ||
366 | msecs_to_jiffies(1000)); | ||
367 | if (time_left > 0) | ||
368 | return 0; | ||
369 | mxr_warn(mdev, "no vsync detected - timeout\n"); | ||
370 | return -ETIME; | ||
371 | } | ||
372 | |||
373 | void mxr_reg_set_mbus_fmt(struct mxr_device *mdev, | ||
374 | struct v4l2_mbus_framefmt *fmt) | ||
375 | { | ||
376 | u32 val = 0; | ||
377 | unsigned long flags; | ||
378 | |||
379 | spin_lock_irqsave(&mdev->reg_slock, flags); | ||
380 | mxr_vsync_set_update(mdev, MXR_DISABLE); | ||
381 | |||
382 | /* selecting colorspace accepted by output */ | ||
383 | if (fmt->colorspace == V4L2_COLORSPACE_JPEG) | ||
384 | val |= MXR_CFG_OUT_YUV444; | ||
385 | else | ||
386 | val |= MXR_CFG_OUT_RGB888; | ||
387 | |||
388 | /* choosing between interlace and progressive mode */ | ||
389 | if (fmt->field == V4L2_FIELD_INTERLACED) | ||
390 | val |= MXR_CFG_SCAN_INTERLACE; | ||
391 | else | ||
392 | val |= MXR_CFG_SCAN_PROGRASSIVE; | ||
393 | |||
394 | /* choosing between porper HD and SD mode */ | ||
395 | if (fmt->height == 480) | ||
396 | val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD; | ||
397 | else if (fmt->height == 576) | ||
398 | val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD; | ||
399 | else if (fmt->height == 720) | ||
400 | val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD; | ||
401 | else if (fmt->height == 1080) | ||
402 | val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD; | ||
403 | else | ||
404 | WARN(1, "unrecognized mbus height %u!\n", fmt->height); | ||
405 | |||
406 | mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK | | ||
407 | MXR_CFG_OUT_MASK); | ||
408 | |||
409 | val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0; | ||
410 | vp_write_mask(mdev, VP_MODE, val, | ||
411 | VP_MODE_LINE_SKIP | VP_MODE_FIELD_ID_AUTO_TOGGLING); | ||
412 | |||
413 | mxr_vsync_set_update(mdev, MXR_ENABLE); | ||
414 | spin_unlock_irqrestore(&mdev->reg_slock, flags); | ||
415 | } | ||
416 | |||
417 | void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en) | ||
418 | { | ||
419 | /* no extra actions need to be done */ | ||
420 | } | ||
421 | |||
422 | void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en) | ||
423 | { | ||
424 | /* no extra actions need to be done */ | ||
425 | } | ||
426 | |||
427 | static const u8 filter_y_horiz_tap8[] = { | ||
428 | 0, -1, -1, -1, -1, -1, -1, -1, | ||
429 | -1, -1, -1, -1, -1, 0, 0, 0, | ||
430 | 0, 2, 4, 5, 6, 6, 6, 6, | ||
431 | 6, 5, 5, 4, 3, 2, 1, 1, | ||
432 | 0, -6, -12, -16, -18, -20, -21, -20, | ||
433 | -20, -18, -16, -13, -10, -8, -5, -2, | ||
434 | 127, 126, 125, 121, 114, 107, 99, 89, | ||
435 | 79, 68, 57, 46, 35, 25, 16, 8, | ||
436 | }; | ||
437 | |||
438 | static const u8 filter_y_vert_tap4[] = { | ||
439 | 0, -3, -6, -8, -8, -8, -8, -7, | ||
440 | -6, -5, -4, -3, -2, -1, -1, 0, | ||
441 | 127, 126, 124, 118, 111, 102, 92, 81, | ||
442 | 70, 59, 48, 37, 27, 19, 11, 5, | ||
443 | 0, 5, 11, 19, 27, 37, 48, 59, | ||
444 | 70, 81, 92, 102, 111, 118, 124, 126, | ||
445 | 0, 0, -1, -1, -2, -3, -4, -5, | ||
446 | -6, -7, -8, -8, -8, -8, -6, -3, | ||
447 | }; | ||
448 | |||
449 | static const u8 filter_cr_horiz_tap4[] = { | ||
450 | 0, -3, -6, -8, -8, -8, -8, -7, | ||
451 | -6, -5, -4, -3, -2, -1, -1, 0, | ||
452 | 127, 126, 124, 118, 111, 102, 92, 81, | ||
453 | 70, 59, 48, 37, 27, 19, 11, 5, | ||
454 | }; | ||
455 | |||
456 | static inline void mxr_reg_vp_filter_set(struct mxr_device *mdev, | ||
457 | int reg_id, const u8 *data, unsigned int size) | ||
458 | { | ||
459 | /* assure 4-byte align */ | ||
460 | BUG_ON(size & 3); | ||
461 | for (; size; size -= 4, reg_id += 4, data += 4) { | ||
462 | u32 val = (data[0] << 24) | (data[1] << 16) | | ||
463 | (data[2] << 8) | data[3]; | ||
464 | vp_write(mdev, reg_id, val); | ||
465 | } | ||
466 | } | ||
467 | |||
468 | static void mxr_reg_vp_default_filter(struct mxr_device *mdev) | ||
469 | { | ||
470 | mxr_reg_vp_filter_set(mdev, VP_POLY8_Y0_LL, | ||
471 | filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8)); | ||
472 | mxr_reg_vp_filter_set(mdev, VP_POLY4_Y0_LL, | ||
473 | filter_y_vert_tap4, sizeof(filter_y_vert_tap4)); | ||
474 | mxr_reg_vp_filter_set(mdev, VP_POLY4_C0_LL, | ||
475 | filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4)); | ||
476 | } | ||
477 | |||
478 | static void mxr_reg_mxr_dump(struct mxr_device *mdev) | ||
479 | { | ||
480 | #define DUMPREG(reg_id) \ | ||
481 | do { \ | ||
482 | mxr_dbg(mdev, #reg_id " = %08x\n", \ | ||
483 | (u32)readl(mdev->res.mxr_regs + reg_id)); \ | ||
484 | } while (0) | ||
485 | |||
486 | DUMPREG(MXR_STATUS); | ||
487 | DUMPREG(MXR_CFG); | ||
488 | DUMPREG(MXR_INT_EN); | ||
489 | DUMPREG(MXR_INT_STATUS); | ||
490 | |||
491 | DUMPREG(MXR_LAYER_CFG); | ||
492 | DUMPREG(MXR_VIDEO_CFG); | ||
493 | |||
494 | DUMPREG(MXR_GRAPHIC0_CFG); | ||
495 | DUMPREG(MXR_GRAPHIC0_BASE); | ||
496 | DUMPREG(MXR_GRAPHIC0_SPAN); | ||
497 | DUMPREG(MXR_GRAPHIC0_WH); | ||
498 | DUMPREG(MXR_GRAPHIC0_SXY); | ||
499 | DUMPREG(MXR_GRAPHIC0_DXY); | ||
500 | |||
501 | DUMPREG(MXR_GRAPHIC1_CFG); | ||
502 | DUMPREG(MXR_GRAPHIC1_BASE); | ||
503 | DUMPREG(MXR_GRAPHIC1_SPAN); | ||
504 | DUMPREG(MXR_GRAPHIC1_WH); | ||
505 | DUMPREG(MXR_GRAPHIC1_SXY); | ||
506 | DUMPREG(MXR_GRAPHIC1_DXY); | ||
507 | #undef DUMPREG | ||
508 | } | ||
509 | |||
510 | static void mxr_reg_vp_dump(struct mxr_device *mdev) | ||
511 | { | ||
512 | #define DUMPREG(reg_id) \ | ||
513 | do { \ | ||
514 | mxr_dbg(mdev, #reg_id " = %08x\n", \ | ||
515 | (u32) readl(mdev->res.vp_regs + reg_id)); \ | ||
516 | } while (0) | ||
517 | |||
518 | |||
519 | DUMPREG(VP_ENABLE); | ||
520 | DUMPREG(VP_SRESET); | ||
521 | DUMPREG(VP_SHADOW_UPDATE); | ||
522 | DUMPREG(VP_FIELD_ID); | ||
523 | DUMPREG(VP_MODE); | ||
524 | DUMPREG(VP_IMG_SIZE_Y); | ||
525 | DUMPREG(VP_IMG_SIZE_C); | ||
526 | DUMPREG(VP_PER_RATE_CTRL); | ||
527 | DUMPREG(VP_TOP_Y_PTR); | ||
528 | DUMPREG(VP_BOT_Y_PTR); | ||
529 | DUMPREG(VP_TOP_C_PTR); | ||
530 | DUMPREG(VP_BOT_C_PTR); | ||
531 | DUMPREG(VP_ENDIAN_MODE); | ||
532 | DUMPREG(VP_SRC_H_POSITION); | ||
533 | DUMPREG(VP_SRC_V_POSITION); | ||
534 | DUMPREG(VP_SRC_WIDTH); | ||
535 | DUMPREG(VP_SRC_HEIGHT); | ||
536 | DUMPREG(VP_DST_H_POSITION); | ||
537 | DUMPREG(VP_DST_V_POSITION); | ||
538 | DUMPREG(VP_DST_WIDTH); | ||
539 | DUMPREG(VP_DST_HEIGHT); | ||
540 | DUMPREG(VP_H_RATIO); | ||
541 | DUMPREG(VP_V_RATIO); | ||
542 | |||
543 | #undef DUMPREG | ||
544 | } | ||
545 | |||
546 | void mxr_reg_dump(struct mxr_device *mdev) | ||
547 | { | ||
548 | mxr_reg_mxr_dump(mdev); | ||
549 | mxr_reg_vp_dump(mdev); | ||
550 | } | ||
551 | |||
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c deleted file mode 100644 index ee74e2b44d69..000000000000 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ /dev/null | |||
@@ -1,1130 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung TV Mixer driver | ||
3 | * | ||
4 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
5 | * | ||
6 | * Tomasz Stanislawski, <t.stanislaws@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 as published | ||
10 | * by the Free Software Foundation. either version 2 of the License, | ||
11 | * or (at your option) any later version | ||
12 | */ | ||
13 | |||
14 | #define pr_fmt(fmt) "s5p-tv (mixer): " fmt | ||
15 | |||
16 | #include "mixer.h" | ||
17 | |||
18 | #include <media/v4l2-ioctl.h> | ||
19 | #include <linux/videodev2.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/timer.h> | ||
24 | #include <media/videobuf2-dma-contig.h> | ||
25 | |||
26 | static int find_reg_callback(struct device *dev, void *p) | ||
27 | { | ||
28 | struct v4l2_subdev **sd = p; | ||
29 | |||
30 | *sd = dev_get_drvdata(dev); | ||
31 | /* non-zero value stops iteration */ | ||
32 | return 1; | ||
33 | } | ||
34 | |||
35 | static struct v4l2_subdev *find_and_register_subdev( | ||
36 | struct mxr_device *mdev, char *module_name) | ||
37 | { | ||
38 | struct device_driver *drv; | ||
39 | struct v4l2_subdev *sd = NULL; | ||
40 | int ret; | ||
41 | |||
42 | /* TODO: add waiting until probe is finished */ | ||
43 | drv = driver_find(module_name, &platform_bus_type); | ||
44 | if (!drv) { | ||
45 | mxr_warn(mdev, "module %s is missing\n", module_name); | ||
46 | return NULL; | ||
47 | } | ||
48 | /* driver refcnt is increased, it is safe to iterate over devices */ | ||
49 | ret = driver_for_each_device(drv, NULL, &sd, find_reg_callback); | ||
50 | /* ret == 0 means that find_reg_callback was never executed */ | ||
51 | if (sd == NULL) { | ||
52 | mxr_warn(mdev, "module %s provides no subdev!\n", module_name); | ||
53 | goto done; | ||
54 | } | ||
55 | /* v4l2_device_register_subdev detects if sd is NULL */ | ||
56 | ret = v4l2_device_register_subdev(&mdev->v4l2_dev, sd); | ||
57 | if (ret) { | ||
58 | mxr_warn(mdev, "failed to register subdev %s\n", sd->name); | ||
59 | sd = NULL; | ||
60 | } | ||
61 | |||
62 | done: | ||
63 | return sd; | ||
64 | } | ||
65 | |||
66 | int mxr_acquire_video(struct mxr_device *mdev, | ||
67 | struct mxr_output_conf *output_conf, int output_count) | ||
68 | { | ||
69 | struct device *dev = mdev->dev; | ||
70 | struct v4l2_device *v4l2_dev = &mdev->v4l2_dev; | ||
71 | int i; | ||
72 | int ret = 0; | ||
73 | struct v4l2_subdev *sd; | ||
74 | |||
75 | strlcpy(v4l2_dev->name, dev_name(mdev->dev), sizeof(v4l2_dev->name)); | ||
76 | /* prepare context for V4L2 device */ | ||
77 | ret = v4l2_device_register(dev, v4l2_dev); | ||
78 | if (ret) { | ||
79 | mxr_err(mdev, "could not register v4l2 device.\n"); | ||
80 | goto fail; | ||
81 | } | ||
82 | |||
83 | vb2_dma_contig_set_max_seg_size(mdev->dev, DMA_BIT_MASK(32)); | ||
84 | |||
85 | /* registering outputs */ | ||
86 | mdev->output_cnt = 0; | ||
87 | for (i = 0; i < output_count; ++i) { | ||
88 | struct mxr_output_conf *conf = &output_conf[i]; | ||
89 | struct mxr_output *out; | ||
90 | |||
91 | sd = find_and_register_subdev(mdev, conf->module_name); | ||
92 | /* trying to register next output */ | ||
93 | if (sd == NULL) | ||
94 | continue; | ||
95 | out = kzalloc(sizeof(*out), GFP_KERNEL); | ||
96 | if (out == NULL) { | ||
97 | mxr_err(mdev, "no memory for '%s'\n", | ||
98 | conf->output_name); | ||
99 | ret = -ENOMEM; | ||
100 | /* registered subdevs are removed in fail_v4l2_dev */ | ||
101 | goto fail_output; | ||
102 | } | ||
103 | strlcpy(out->name, conf->output_name, sizeof(out->name)); | ||
104 | out->sd = sd; | ||
105 | out->cookie = conf->cookie; | ||
106 | mdev->output[mdev->output_cnt++] = out; | ||
107 | mxr_info(mdev, "added output '%s' from module '%s'\n", | ||
108 | conf->output_name, conf->module_name); | ||
109 | /* checking if maximal number of outputs is reached */ | ||
110 | if (mdev->output_cnt >= MXR_MAX_OUTPUTS) | ||
111 | break; | ||
112 | } | ||
113 | |||
114 | if (mdev->output_cnt == 0) { | ||
115 | mxr_err(mdev, "failed to register any output\n"); | ||
116 | ret = -ENODEV; | ||
117 | /* skipping fail_output because there is nothing to free */ | ||
118 | goto fail_v4l2_dev; | ||
119 | } | ||
120 | |||
121 | return 0; | ||
122 | |||
123 | fail_output: | ||
124 | /* kfree is NULL-safe */ | ||
125 | for (i = 0; i < mdev->output_cnt; ++i) | ||
126 | kfree(mdev->output[i]); | ||
127 | memset(mdev->output, 0, sizeof(mdev->output)); | ||
128 | |||
129 | fail_v4l2_dev: | ||
130 | /* NOTE: automatically unregister all subdevs */ | ||
131 | v4l2_device_unregister(v4l2_dev); | ||
132 | |||
133 | fail: | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | void mxr_release_video(struct mxr_device *mdev) | ||
138 | { | ||
139 | int i; | ||
140 | |||
141 | /* kfree is NULL-safe */ | ||
142 | for (i = 0; i < mdev->output_cnt; ++i) | ||
143 | kfree(mdev->output[i]); | ||
144 | |||
145 | vb2_dma_contig_clear_max_seg_size(mdev->dev); | ||
146 | v4l2_device_unregister(&mdev->v4l2_dev); | ||
147 | } | ||
148 | |||
149 | static int mxr_querycap(struct file *file, void *priv, | ||
150 | struct v4l2_capability *cap) | ||
151 | { | ||
152 | struct mxr_layer *layer = video_drvdata(file); | ||
153 | |||
154 | mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); | ||
155 | |||
156 | strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof(cap->driver)); | ||
157 | strlcpy(cap->card, layer->vfd.name, sizeof(cap->card)); | ||
158 | sprintf(cap->bus_info, "%d", layer->idx); | ||
159 | cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT_MPLANE; | ||
160 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo) | ||
166 | { | ||
167 | mxr_dbg(mdev, "src.full_size = (%u, %u)\n", | ||
168 | geo->src.full_width, geo->src.full_height); | ||
169 | mxr_dbg(mdev, "src.size = (%u, %u)\n", | ||
170 | geo->src.width, geo->src.height); | ||
171 | mxr_dbg(mdev, "src.offset = (%u, %u)\n", | ||
172 | geo->src.x_offset, geo->src.y_offset); | ||
173 | mxr_dbg(mdev, "dst.full_size = (%u, %u)\n", | ||
174 | geo->dst.full_width, geo->dst.full_height); | ||
175 | mxr_dbg(mdev, "dst.size = (%u, %u)\n", | ||
176 | geo->dst.width, geo->dst.height); | ||
177 | mxr_dbg(mdev, "dst.offset = (%u, %u)\n", | ||
178 | geo->dst.x_offset, geo->dst.y_offset); | ||
179 | mxr_dbg(mdev, "ratio = (%u, %u)\n", | ||
180 | geo->x_ratio, geo->y_ratio); | ||
181 | } | ||
182 | |||
183 | static void mxr_layer_default_geo(struct mxr_layer *layer) | ||
184 | { | ||
185 | struct mxr_device *mdev = layer->mdev; | ||
186 | struct v4l2_mbus_framefmt mbus_fmt; | ||
187 | |||
188 | memset(&layer->geo, 0, sizeof(layer->geo)); | ||
189 | |||
190 | mxr_get_mbus_fmt(mdev, &mbus_fmt); | ||
191 | |||
192 | layer->geo.dst.full_width = mbus_fmt.width; | ||
193 | layer->geo.dst.full_height = mbus_fmt.height; | ||
194 | layer->geo.dst.width = layer->geo.dst.full_width; | ||
195 | layer->geo.dst.height = layer->geo.dst.full_height; | ||
196 | layer->geo.dst.field = mbus_fmt.field; | ||
197 | |||
198 | layer->geo.src.full_width = mbus_fmt.width; | ||
199 | layer->geo.src.full_height = mbus_fmt.height; | ||
200 | layer->geo.src.width = layer->geo.src.full_width; | ||
201 | layer->geo.src.height = layer->geo.src.full_height; | ||
202 | |||
203 | mxr_geometry_dump(mdev, &layer->geo); | ||
204 | layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0); | ||
205 | mxr_geometry_dump(mdev, &layer->geo); | ||
206 | } | ||
207 | |||
208 | static void mxr_layer_update_output(struct mxr_layer *layer) | ||
209 | { | ||
210 | struct mxr_device *mdev = layer->mdev; | ||
211 | struct v4l2_mbus_framefmt mbus_fmt; | ||
212 | |||
213 | mxr_get_mbus_fmt(mdev, &mbus_fmt); | ||
214 | /* checking if update is needed */ | ||
215 | if (layer->geo.dst.full_width == mbus_fmt.width && | ||
216 | layer->geo.dst.full_height == mbus_fmt.width) | ||
217 | return; | ||
218 | |||
219 | layer->geo.dst.full_width = mbus_fmt.width; | ||
220 | layer->geo.dst.full_height = mbus_fmt.height; | ||
221 | layer->geo.dst.field = mbus_fmt.field; | ||
222 | layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0); | ||
223 | |||
224 | mxr_geometry_dump(mdev, &layer->geo); | ||
225 | } | ||
226 | |||
227 | static const struct mxr_format *find_format_by_fourcc( | ||
228 | struct mxr_layer *layer, unsigned long fourcc); | ||
229 | static const struct mxr_format *find_format_by_index( | ||
230 | struct mxr_layer *layer, unsigned long index); | ||
231 | |||
232 | static int mxr_enum_fmt(struct file *file, void *priv, | ||
233 | struct v4l2_fmtdesc *f) | ||
234 | { | ||
235 | struct mxr_layer *layer = video_drvdata(file); | ||
236 | struct mxr_device *mdev = layer->mdev; | ||
237 | const struct mxr_format *fmt; | ||
238 | |||
239 | mxr_dbg(mdev, "%s\n", __func__); | ||
240 | fmt = find_format_by_index(layer, f->index); | ||
241 | if (fmt == NULL) | ||
242 | return -EINVAL; | ||
243 | |||
244 | strlcpy(f->description, fmt->name, sizeof(f->description)); | ||
245 | f->pixelformat = fmt->fourcc; | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static unsigned int divup(unsigned int divident, unsigned int divisor) | ||
251 | { | ||
252 | return (divident + divisor - 1) / divisor; | ||
253 | } | ||
254 | |||
255 | unsigned long mxr_get_plane_size(const struct mxr_block *blk, | ||
256 | unsigned int width, unsigned int height) | ||
257 | { | ||
258 | unsigned int bl_width = divup(width, blk->width); | ||
259 | unsigned int bl_height = divup(height, blk->height); | ||
260 | |||
261 | return bl_width * bl_height * blk->size; | ||
262 | } | ||
263 | |||
264 | static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes, | ||
265 | const struct mxr_format *fmt, u32 width, u32 height) | ||
266 | { | ||
267 | int i; | ||
268 | |||
269 | /* checking if nothing to fill */ | ||
270 | if (!planes) | ||
271 | return; | ||
272 | |||
273 | memset(planes, 0, sizeof(*planes) * fmt->num_subframes); | ||
274 | for (i = 0; i < fmt->num_planes; ++i) { | ||
275 | struct v4l2_plane_pix_format *plane = planes | ||
276 | + fmt->plane2subframe[i]; | ||
277 | const struct mxr_block *blk = &fmt->plane[i]; | ||
278 | u32 bl_width = divup(width, blk->width); | ||
279 | u32 bl_height = divup(height, blk->height); | ||
280 | u32 sizeimage = bl_width * bl_height * blk->size; | ||
281 | u32 bytesperline = bl_width * blk->size / blk->height; | ||
282 | |||
283 | plane->sizeimage += sizeimage; | ||
284 | plane->bytesperline = max(plane->bytesperline, bytesperline); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static int mxr_g_fmt(struct file *file, void *priv, | ||
289 | struct v4l2_format *f) | ||
290 | { | ||
291 | struct mxr_layer *layer = video_drvdata(file); | ||
292 | struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; | ||
293 | |||
294 | mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); | ||
295 | |||
296 | pix->width = layer->geo.src.full_width; | ||
297 | pix->height = layer->geo.src.full_height; | ||
298 | pix->field = V4L2_FIELD_NONE; | ||
299 | pix->pixelformat = layer->fmt->fourcc; | ||
300 | pix->colorspace = layer->fmt->colorspace; | ||
301 | mxr_mplane_fill(pix->plane_fmt, layer->fmt, pix->width, pix->height); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int mxr_s_fmt(struct file *file, void *priv, | ||
307 | struct v4l2_format *f) | ||
308 | { | ||
309 | struct mxr_layer *layer = video_drvdata(file); | ||
310 | const struct mxr_format *fmt; | ||
311 | struct v4l2_pix_format_mplane *pix; | ||
312 | struct mxr_device *mdev = layer->mdev; | ||
313 | struct mxr_geometry *geo = &layer->geo; | ||
314 | |||
315 | mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__); | ||
316 | |||
317 | pix = &f->fmt.pix_mp; | ||
318 | fmt = find_format_by_fourcc(layer, pix->pixelformat); | ||
319 | if (fmt == NULL) { | ||
320 | mxr_warn(mdev, "not recognized fourcc: %08x\n", | ||
321 | pix->pixelformat); | ||
322 | return -EINVAL; | ||
323 | } | ||
324 | layer->fmt = fmt; | ||
325 | /* set source size to highest accepted value */ | ||
326 | geo->src.full_width = max(geo->dst.full_width, pix->width); | ||
327 | geo->src.full_height = max(geo->dst.full_height, pix->height); | ||
328 | layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0); | ||
329 | mxr_geometry_dump(mdev, &layer->geo); | ||
330 | /* set cropping to total visible screen */ | ||
331 | geo->src.width = pix->width; | ||
332 | geo->src.height = pix->height; | ||
333 | geo->src.x_offset = 0; | ||
334 | geo->src.y_offset = 0; | ||
335 | /* assure consistency of geometry */ | ||
336 | layer->ops.fix_geometry(layer, MXR_GEOMETRY_CROP, MXR_NO_OFFSET); | ||
337 | mxr_geometry_dump(mdev, &layer->geo); | ||
338 | /* set full size to lowest possible value */ | ||
339 | geo->src.full_width = 0; | ||
340 | geo->src.full_height = 0; | ||
341 | layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0); | ||
342 | mxr_geometry_dump(mdev, &layer->geo); | ||
343 | |||
344 | /* returning results */ | ||
345 | mxr_g_fmt(file, priv, f); | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int mxr_g_selection(struct file *file, void *fh, | ||
351 | struct v4l2_selection *s) | ||
352 | { | ||
353 | struct mxr_layer *layer = video_drvdata(file); | ||
354 | struct mxr_geometry *geo = &layer->geo; | ||
355 | |||
356 | mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); | ||
357 | |||
358 | if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && | ||
359 | s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
360 | return -EINVAL; | ||
361 | |||
362 | switch (s->target) { | ||
363 | case V4L2_SEL_TGT_CROP: | ||
364 | s->r.left = geo->src.x_offset; | ||
365 | s->r.top = geo->src.y_offset; | ||
366 | s->r.width = geo->src.width; | ||
367 | s->r.height = geo->src.height; | ||
368 | break; | ||
369 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
370 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
371 | s->r.left = 0; | ||
372 | s->r.top = 0; | ||
373 | s->r.width = geo->src.full_width; | ||
374 | s->r.height = geo->src.full_height; | ||
375 | break; | ||
376 | case V4L2_SEL_TGT_COMPOSE: | ||
377 | case V4L2_SEL_TGT_COMPOSE_PADDED: | ||
378 | s->r.left = geo->dst.x_offset; | ||
379 | s->r.top = geo->dst.y_offset; | ||
380 | s->r.width = geo->dst.width; | ||
381 | s->r.height = geo->dst.height; | ||
382 | break; | ||
383 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: | ||
384 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
385 | s->r.left = 0; | ||
386 | s->r.top = 0; | ||
387 | s->r.width = geo->dst.full_width; | ||
388 | s->r.height = geo->dst.full_height; | ||
389 | break; | ||
390 | default: | ||
391 | return -EINVAL; | ||
392 | } | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | /* returns 1 if rectangle 'a' is inside 'b' */ | ||
398 | static int mxr_is_rect_inside(struct v4l2_rect *a, struct v4l2_rect *b) | ||
399 | { | ||
400 | if (a->left < b->left) | ||
401 | return 0; | ||
402 | if (a->top < b->top) | ||
403 | return 0; | ||
404 | if (a->left + a->width > b->left + b->width) | ||
405 | return 0; | ||
406 | if (a->top + a->height > b->top + b->height) | ||
407 | return 0; | ||
408 | return 1; | ||
409 | } | ||
410 | |||
411 | static int mxr_s_selection(struct file *file, void *fh, | ||
412 | struct v4l2_selection *s) | ||
413 | { | ||
414 | struct mxr_layer *layer = video_drvdata(file); | ||
415 | struct mxr_geometry *geo = &layer->geo; | ||
416 | struct mxr_crop *target = NULL; | ||
417 | enum mxr_geometry_stage stage; | ||
418 | struct mxr_geometry tmp; | ||
419 | struct v4l2_rect res; | ||
420 | |||
421 | memset(&res, 0, sizeof(res)); | ||
422 | |||
423 | mxr_dbg(layer->mdev, "%s: rect: %dx%d@%d,%d\n", __func__, | ||
424 | s->r.width, s->r.height, s->r.left, s->r.top); | ||
425 | |||
426 | if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && | ||
427 | s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
428 | return -EINVAL; | ||
429 | |||
430 | switch (s->target) { | ||
431 | /* ignore read-only targets */ | ||
432 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
433 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
434 | res.width = geo->src.full_width; | ||
435 | res.height = geo->src.full_height; | ||
436 | break; | ||
437 | |||
438 | /* ignore read-only targets */ | ||
439 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: | ||
440 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
441 | res.width = geo->dst.full_width; | ||
442 | res.height = geo->dst.full_height; | ||
443 | break; | ||
444 | |||
445 | case V4L2_SEL_TGT_CROP: | ||
446 | target = &geo->src; | ||
447 | stage = MXR_GEOMETRY_CROP; | ||
448 | break; | ||
449 | case V4L2_SEL_TGT_COMPOSE: | ||
450 | case V4L2_SEL_TGT_COMPOSE_PADDED: | ||
451 | target = &geo->dst; | ||
452 | stage = MXR_GEOMETRY_COMPOSE; | ||
453 | break; | ||
454 | default: | ||
455 | return -EINVAL; | ||
456 | } | ||
457 | /* apply change and update geometry if needed */ | ||
458 | if (target) { | ||
459 | /* backup current geometry if setup fails */ | ||
460 | memcpy(&tmp, geo, sizeof(tmp)); | ||
461 | |||
462 | /* apply requested selection */ | ||
463 | target->x_offset = s->r.left; | ||
464 | target->y_offset = s->r.top; | ||
465 | target->width = s->r.width; | ||
466 | target->height = s->r.height; | ||
467 | |||
468 | layer->ops.fix_geometry(layer, stage, s->flags); | ||
469 | |||
470 | /* retrieve update selection rectangle */ | ||
471 | res.left = target->x_offset; | ||
472 | res.top = target->y_offset; | ||
473 | res.width = target->width; | ||
474 | res.height = target->height; | ||
475 | |||
476 | mxr_geometry_dump(layer->mdev, &layer->geo); | ||
477 | } | ||
478 | |||
479 | /* checking if the rectangle satisfies constraints */ | ||
480 | if ((s->flags & V4L2_SEL_FLAG_LE) && !mxr_is_rect_inside(&res, &s->r)) | ||
481 | goto fail; | ||
482 | if ((s->flags & V4L2_SEL_FLAG_GE) && !mxr_is_rect_inside(&s->r, &res)) | ||
483 | goto fail; | ||
484 | |||
485 | /* return result rectangle */ | ||
486 | s->r = res; | ||
487 | |||
488 | return 0; | ||
489 | fail: | ||
490 | /* restore old geometry, which is not touched if target is NULL */ | ||
491 | if (target) | ||
492 | memcpy(geo, &tmp, sizeof(tmp)); | ||
493 | return -ERANGE; | ||
494 | } | ||
495 | |||
496 | static int mxr_enum_dv_timings(struct file *file, void *fh, | ||
497 | struct v4l2_enum_dv_timings *timings) | ||
498 | { | ||
499 | struct mxr_layer *layer = video_drvdata(file); | ||
500 | struct mxr_device *mdev = layer->mdev; | ||
501 | int ret; | ||
502 | |||
503 | timings->pad = 0; | ||
504 | |||
505 | /* lock protects from changing sd_out */ | ||
506 | mutex_lock(&mdev->mutex); | ||
507 | ret = v4l2_subdev_call(to_outsd(mdev), pad, enum_dv_timings, timings); | ||
508 | mutex_unlock(&mdev->mutex); | ||
509 | |||
510 | return ret ? -EINVAL : 0; | ||
511 | } | ||
512 | |||
513 | static int mxr_s_dv_timings(struct file *file, void *fh, | ||
514 | struct v4l2_dv_timings *timings) | ||
515 | { | ||
516 | struct mxr_layer *layer = video_drvdata(file); | ||
517 | struct mxr_device *mdev = layer->mdev; | ||
518 | int ret; | ||
519 | |||
520 | /* lock protects from changing sd_out */ | ||
521 | mutex_lock(&mdev->mutex); | ||
522 | |||
523 | /* timings change cannot be done while there is an entity | ||
524 | * dependent on output configuration | ||
525 | */ | ||
526 | if (mdev->n_output > 0) { | ||
527 | mutex_unlock(&mdev->mutex); | ||
528 | return -EBUSY; | ||
529 | } | ||
530 | |||
531 | ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_timings, timings); | ||
532 | |||
533 | mutex_unlock(&mdev->mutex); | ||
534 | |||
535 | mxr_layer_update_output(layer); | ||
536 | |||
537 | /* any failure should return EINVAL according to V4L2 doc */ | ||
538 | return ret ? -EINVAL : 0; | ||
539 | } | ||
540 | |||
541 | static int mxr_g_dv_timings(struct file *file, void *fh, | ||
542 | struct v4l2_dv_timings *timings) | ||
543 | { | ||
544 | struct mxr_layer *layer = video_drvdata(file); | ||
545 | struct mxr_device *mdev = layer->mdev; | ||
546 | int ret; | ||
547 | |||
548 | /* lock protects from changing sd_out */ | ||
549 | mutex_lock(&mdev->mutex); | ||
550 | ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_timings, timings); | ||
551 | mutex_unlock(&mdev->mutex); | ||
552 | |||
553 | return ret ? -EINVAL : 0; | ||
554 | } | ||
555 | |||
556 | static int mxr_dv_timings_cap(struct file *file, void *fh, | ||
557 | struct v4l2_dv_timings_cap *cap) | ||
558 | { | ||
559 | struct mxr_layer *layer = video_drvdata(file); | ||
560 | struct mxr_device *mdev = layer->mdev; | ||
561 | int ret; | ||
562 | |||
563 | cap->pad = 0; | ||
564 | |||
565 | /* lock protects from changing sd_out */ | ||
566 | mutex_lock(&mdev->mutex); | ||
567 | ret = v4l2_subdev_call(to_outsd(mdev), pad, dv_timings_cap, cap); | ||
568 | mutex_unlock(&mdev->mutex); | ||
569 | |||
570 | return ret ? -EINVAL : 0; | ||
571 | } | ||
572 | |||
573 | static int mxr_s_std(struct file *file, void *fh, v4l2_std_id norm) | ||
574 | { | ||
575 | struct mxr_layer *layer = video_drvdata(file); | ||
576 | struct mxr_device *mdev = layer->mdev; | ||
577 | int ret; | ||
578 | |||
579 | /* lock protects from changing sd_out */ | ||
580 | mutex_lock(&mdev->mutex); | ||
581 | |||
582 | /* standard change cannot be done while there is an entity | ||
583 | * dependent on output configuration | ||
584 | */ | ||
585 | if (mdev->n_output > 0) { | ||
586 | mutex_unlock(&mdev->mutex); | ||
587 | return -EBUSY; | ||
588 | } | ||
589 | |||
590 | ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, norm); | ||
591 | |||
592 | mutex_unlock(&mdev->mutex); | ||
593 | |||
594 | mxr_layer_update_output(layer); | ||
595 | |||
596 | return ret ? -EINVAL : 0; | ||
597 | } | ||
598 | |||
599 | static int mxr_g_std(struct file *file, void *fh, v4l2_std_id *norm) | ||
600 | { | ||
601 | struct mxr_layer *layer = video_drvdata(file); | ||
602 | struct mxr_device *mdev = layer->mdev; | ||
603 | int ret; | ||
604 | |||
605 | /* lock protects from changing sd_out */ | ||
606 | mutex_lock(&mdev->mutex); | ||
607 | ret = v4l2_subdev_call(to_outsd(mdev), video, g_std_output, norm); | ||
608 | mutex_unlock(&mdev->mutex); | ||
609 | |||
610 | return ret ? -EINVAL : 0; | ||
611 | } | ||
612 | |||
613 | static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a) | ||
614 | { | ||
615 | struct mxr_layer *layer = video_drvdata(file); | ||
616 | struct mxr_device *mdev = layer->mdev; | ||
617 | struct mxr_output *out; | ||
618 | struct v4l2_subdev *sd; | ||
619 | |||
620 | if (a->index >= mdev->output_cnt) | ||
621 | return -EINVAL; | ||
622 | out = mdev->output[a->index]; | ||
623 | BUG_ON(out == NULL); | ||
624 | sd = out->sd; | ||
625 | strlcpy(a->name, out->name, sizeof(a->name)); | ||
626 | |||
627 | /* try to obtain supported tv norms */ | ||
628 | v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std); | ||
629 | a->capabilities = 0; | ||
630 | if (sd->ops->video && sd->ops->video->s_dv_timings) | ||
631 | a->capabilities |= V4L2_OUT_CAP_DV_TIMINGS; | ||
632 | if (sd->ops->video && sd->ops->video->s_std_output) | ||
633 | a->capabilities |= V4L2_OUT_CAP_STD; | ||
634 | a->type = V4L2_OUTPUT_TYPE_ANALOG; | ||
635 | |||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int mxr_s_output(struct file *file, void *fh, unsigned int i) | ||
640 | { | ||
641 | struct video_device *vfd = video_devdata(file); | ||
642 | struct mxr_layer *layer = video_drvdata(file); | ||
643 | struct mxr_device *mdev = layer->mdev; | ||
644 | |||
645 | if (i >= mdev->output_cnt || mdev->output[i] == NULL) | ||
646 | return -EINVAL; | ||
647 | |||
648 | mutex_lock(&mdev->mutex); | ||
649 | if (mdev->n_output > 0) { | ||
650 | mutex_unlock(&mdev->mutex); | ||
651 | return -EBUSY; | ||
652 | } | ||
653 | mdev->current_output = i; | ||
654 | vfd->tvnorms = 0; | ||
655 | v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output, | ||
656 | &vfd->tvnorms); | ||
657 | mutex_unlock(&mdev->mutex); | ||
658 | |||
659 | /* update layers geometry */ | ||
660 | mxr_layer_update_output(layer); | ||
661 | |||
662 | mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms); | ||
663 | |||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static int mxr_g_output(struct file *file, void *fh, unsigned int *p) | ||
668 | { | ||
669 | struct mxr_layer *layer = video_drvdata(file); | ||
670 | struct mxr_device *mdev = layer->mdev; | ||
671 | |||
672 | mutex_lock(&mdev->mutex); | ||
673 | *p = mdev->current_output; | ||
674 | mutex_unlock(&mdev->mutex); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static int mxr_reqbufs(struct file *file, void *priv, | ||
680 | struct v4l2_requestbuffers *p) | ||
681 | { | ||
682 | struct mxr_layer *layer = video_drvdata(file); | ||
683 | |||
684 | mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); | ||
685 | return vb2_reqbufs(&layer->vb_queue, p); | ||
686 | } | ||
687 | |||
688 | static int mxr_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) | ||
689 | { | ||
690 | struct mxr_layer *layer = video_drvdata(file); | ||
691 | |||
692 | mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); | ||
693 | return vb2_querybuf(&layer->vb_queue, p); | ||
694 | } | ||
695 | |||
696 | static int mxr_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) | ||
697 | { | ||
698 | struct mxr_layer *layer = video_drvdata(file); | ||
699 | |||
700 | mxr_dbg(layer->mdev, "%s:%d(%d)\n", __func__, __LINE__, p->index); | ||
701 | return vb2_qbuf(&layer->vb_queue, p); | ||
702 | } | ||
703 | |||
704 | static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) | ||
705 | { | ||
706 | struct mxr_layer *layer = video_drvdata(file); | ||
707 | |||
708 | mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); | ||
709 | return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK); | ||
710 | } | ||
711 | |||
712 | static int mxr_expbuf(struct file *file, void *priv, | ||
713 | struct v4l2_exportbuffer *eb) | ||
714 | { | ||
715 | struct mxr_layer *layer = video_drvdata(file); | ||
716 | |||
717 | mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); | ||
718 | return vb2_expbuf(&layer->vb_queue, eb); | ||
719 | } | ||
720 | |||
721 | static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i) | ||
722 | { | ||
723 | struct mxr_layer *layer = video_drvdata(file); | ||
724 | |||
725 | mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); | ||
726 | return vb2_streamon(&layer->vb_queue, i); | ||
727 | } | ||
728 | |||
729 | static int mxr_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | ||
730 | { | ||
731 | struct mxr_layer *layer = video_drvdata(file); | ||
732 | |||
733 | mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); | ||
734 | return vb2_streamoff(&layer->vb_queue, i); | ||
735 | } | ||
736 | |||
737 | static const struct v4l2_ioctl_ops mxr_ioctl_ops = { | ||
738 | .vidioc_querycap = mxr_querycap, | ||
739 | /* format handling */ | ||
740 | .vidioc_enum_fmt_vid_out_mplane = mxr_enum_fmt, | ||
741 | .vidioc_s_fmt_vid_out_mplane = mxr_s_fmt, | ||
742 | .vidioc_g_fmt_vid_out_mplane = mxr_g_fmt, | ||
743 | /* buffer control */ | ||
744 | .vidioc_reqbufs = mxr_reqbufs, | ||
745 | .vidioc_querybuf = mxr_querybuf, | ||
746 | .vidioc_qbuf = mxr_qbuf, | ||
747 | .vidioc_dqbuf = mxr_dqbuf, | ||
748 | .vidioc_expbuf = mxr_expbuf, | ||
749 | /* Streaming control */ | ||
750 | .vidioc_streamon = mxr_streamon, | ||
751 | .vidioc_streamoff = mxr_streamoff, | ||
752 | /* DV Timings functions */ | ||
753 | .vidioc_enum_dv_timings = mxr_enum_dv_timings, | ||
754 | .vidioc_s_dv_timings = mxr_s_dv_timings, | ||
755 | .vidioc_g_dv_timings = mxr_g_dv_timings, | ||
756 | .vidioc_dv_timings_cap = mxr_dv_timings_cap, | ||
757 | /* analog TV standard functions */ | ||
758 | .vidioc_s_std = mxr_s_std, | ||
759 | .vidioc_g_std = mxr_g_std, | ||
760 | /* Output handling */ | ||
761 | .vidioc_enum_output = mxr_enum_output, | ||
762 | .vidioc_s_output = mxr_s_output, | ||
763 | .vidioc_g_output = mxr_g_output, | ||
764 | /* selection ioctls */ | ||
765 | .vidioc_g_selection = mxr_g_selection, | ||
766 | .vidioc_s_selection = mxr_s_selection, | ||
767 | }; | ||
768 | |||
769 | static int mxr_video_open(struct file *file) | ||
770 | { | ||
771 | struct mxr_layer *layer = video_drvdata(file); | ||
772 | struct mxr_device *mdev = layer->mdev; | ||
773 | int ret = 0; | ||
774 | |||
775 | mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__); | ||
776 | if (mutex_lock_interruptible(&layer->mutex)) | ||
777 | return -ERESTARTSYS; | ||
778 | /* assure device probe is finished */ | ||
779 | wait_for_device_probe(); | ||
780 | /* creating context for file descriptor */ | ||
781 | ret = v4l2_fh_open(file); | ||
782 | if (ret) { | ||
783 | mxr_err(mdev, "v4l2_fh_open failed\n"); | ||
784 | goto unlock; | ||
785 | } | ||
786 | |||
787 | /* leaving if layer is already initialized */ | ||
788 | if (!v4l2_fh_is_singular_file(file)) | ||
789 | goto unlock; | ||
790 | |||
791 | /* FIXME: should power be enabled on open? */ | ||
792 | ret = mxr_power_get(mdev); | ||
793 | if (ret) { | ||
794 | mxr_err(mdev, "power on failed\n"); | ||
795 | goto fail_fh_open; | ||
796 | } | ||
797 | |||
798 | ret = vb2_queue_init(&layer->vb_queue); | ||
799 | if (ret != 0) { | ||
800 | mxr_err(mdev, "failed to initialize vb2 queue\n"); | ||
801 | goto fail_power; | ||
802 | } | ||
803 | /* set default format, first on the list */ | ||
804 | layer->fmt = layer->fmt_array[0]; | ||
805 | /* setup default geometry */ | ||
806 | mxr_layer_default_geo(layer); | ||
807 | mutex_unlock(&layer->mutex); | ||
808 | |||
809 | return 0; | ||
810 | |||
811 | fail_power: | ||
812 | mxr_power_put(mdev); | ||
813 | |||
814 | fail_fh_open: | ||
815 | v4l2_fh_release(file); | ||
816 | |||
817 | unlock: | ||
818 | mutex_unlock(&layer->mutex); | ||
819 | |||
820 | return ret; | ||
821 | } | ||
822 | |||
823 | static unsigned int | ||
824 | mxr_video_poll(struct file *file, struct poll_table_struct *wait) | ||
825 | { | ||
826 | struct mxr_layer *layer = video_drvdata(file); | ||
827 | unsigned int res; | ||
828 | |||
829 | mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); | ||
830 | |||
831 | mutex_lock(&layer->mutex); | ||
832 | res = vb2_poll(&layer->vb_queue, file, wait); | ||
833 | mutex_unlock(&layer->mutex); | ||
834 | return res; | ||
835 | } | ||
836 | |||
837 | static int mxr_video_mmap(struct file *file, struct vm_area_struct *vma) | ||
838 | { | ||
839 | struct mxr_layer *layer = video_drvdata(file); | ||
840 | int ret; | ||
841 | |||
842 | mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); | ||
843 | |||
844 | if (mutex_lock_interruptible(&layer->mutex)) | ||
845 | return -ERESTARTSYS; | ||
846 | ret = vb2_mmap(&layer->vb_queue, vma); | ||
847 | mutex_unlock(&layer->mutex); | ||
848 | return ret; | ||
849 | } | ||
850 | |||
851 | static int mxr_video_release(struct file *file) | ||
852 | { | ||
853 | struct mxr_layer *layer = video_drvdata(file); | ||
854 | |||
855 | mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); | ||
856 | mutex_lock(&layer->mutex); | ||
857 | if (v4l2_fh_is_singular_file(file)) { | ||
858 | vb2_queue_release(&layer->vb_queue); | ||
859 | mxr_power_put(layer->mdev); | ||
860 | } | ||
861 | v4l2_fh_release(file); | ||
862 | mutex_unlock(&layer->mutex); | ||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | static const struct v4l2_file_operations mxr_fops = { | ||
867 | .owner = THIS_MODULE, | ||
868 | .open = mxr_video_open, | ||
869 | .poll = mxr_video_poll, | ||
870 | .mmap = mxr_video_mmap, | ||
871 | .release = mxr_video_release, | ||
872 | .unlocked_ioctl = video_ioctl2, | ||
873 | }; | ||
874 | |||
875 | static int queue_setup(struct vb2_queue *vq, | ||
876 | unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], | ||
877 | struct device *alloc_devs[]) | ||
878 | { | ||
879 | struct mxr_layer *layer = vb2_get_drv_priv(vq); | ||
880 | const struct mxr_format *fmt = layer->fmt; | ||
881 | int i; | ||
882 | struct mxr_device *mdev = layer->mdev; | ||
883 | struct v4l2_plane_pix_format planes[3]; | ||
884 | |||
885 | mxr_dbg(mdev, "%s\n", __func__); | ||
886 | /* checking if format was configured */ | ||
887 | if (fmt == NULL) | ||
888 | return -EINVAL; | ||
889 | mxr_dbg(mdev, "fmt = %s\n", fmt->name); | ||
890 | mxr_mplane_fill(planes, fmt, layer->geo.src.full_width, | ||
891 | layer->geo.src.full_height); | ||
892 | |||
893 | *nplanes = fmt->num_subframes; | ||
894 | for (i = 0; i < fmt->num_subframes; ++i) { | ||
895 | sizes[i] = planes[i].sizeimage; | ||
896 | mxr_dbg(mdev, "size[%d] = %08x\n", i, sizes[i]); | ||
897 | } | ||
898 | |||
899 | if (*nbuffers == 0) | ||
900 | *nbuffers = 1; | ||
901 | |||
902 | return 0; | ||
903 | } | ||
904 | |||
905 | static void buf_queue(struct vb2_buffer *vb) | ||
906 | { | ||
907 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
908 | struct mxr_buffer *buffer = container_of(vbuf, struct mxr_buffer, vb); | ||
909 | struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue); | ||
910 | struct mxr_device *mdev = layer->mdev; | ||
911 | unsigned long flags; | ||
912 | |||
913 | spin_lock_irqsave(&layer->enq_slock, flags); | ||
914 | list_add_tail(&buffer->list, &layer->enq_list); | ||
915 | spin_unlock_irqrestore(&layer->enq_slock, flags); | ||
916 | |||
917 | mxr_dbg(mdev, "queuing buffer\n"); | ||
918 | } | ||
919 | |||
920 | static int start_streaming(struct vb2_queue *vq, unsigned int count) | ||
921 | { | ||
922 | struct mxr_layer *layer = vb2_get_drv_priv(vq); | ||
923 | struct mxr_device *mdev = layer->mdev; | ||
924 | unsigned long flags; | ||
925 | |||
926 | mxr_dbg(mdev, "%s\n", __func__); | ||
927 | |||
928 | /* block any changes in output configuration */ | ||
929 | mxr_output_get(mdev); | ||
930 | |||
931 | mxr_layer_update_output(layer); | ||
932 | layer->ops.format_set(layer); | ||
933 | /* enabling layer in hardware */ | ||
934 | spin_lock_irqsave(&layer->enq_slock, flags); | ||
935 | layer->state = MXR_LAYER_STREAMING; | ||
936 | spin_unlock_irqrestore(&layer->enq_slock, flags); | ||
937 | |||
938 | layer->ops.stream_set(layer, MXR_ENABLE); | ||
939 | mxr_streamer_get(mdev); | ||
940 | |||
941 | return 0; | ||
942 | } | ||
943 | |||
944 | static void mxr_watchdog(unsigned long arg) | ||
945 | { | ||
946 | struct mxr_layer *layer = (struct mxr_layer *) arg; | ||
947 | struct mxr_device *mdev = layer->mdev; | ||
948 | unsigned long flags; | ||
949 | |||
950 | mxr_err(mdev, "watchdog fired for layer %s\n", layer->vfd.name); | ||
951 | |||
952 | spin_lock_irqsave(&layer->enq_slock, flags); | ||
953 | |||
954 | if (layer->update_buf == layer->shadow_buf) | ||
955 | layer->update_buf = NULL; | ||
956 | if (layer->update_buf) { | ||
957 | vb2_buffer_done(&layer->update_buf->vb.vb2_buf, | ||
958 | VB2_BUF_STATE_ERROR); | ||
959 | layer->update_buf = NULL; | ||
960 | } | ||
961 | if (layer->shadow_buf) { | ||
962 | vb2_buffer_done(&layer->shadow_buf->vb.vb2_buf, | ||
963 | VB2_BUF_STATE_ERROR); | ||
964 | layer->shadow_buf = NULL; | ||
965 | } | ||
966 | spin_unlock_irqrestore(&layer->enq_slock, flags); | ||
967 | } | ||
968 | |||
969 | static void stop_streaming(struct vb2_queue *vq) | ||
970 | { | ||
971 | struct mxr_layer *layer = vb2_get_drv_priv(vq); | ||
972 | struct mxr_device *mdev = layer->mdev; | ||
973 | unsigned long flags; | ||
974 | struct timer_list watchdog; | ||
975 | struct mxr_buffer *buf, *buf_tmp; | ||
976 | |||
977 | mxr_dbg(mdev, "%s\n", __func__); | ||
978 | |||
979 | spin_lock_irqsave(&layer->enq_slock, flags); | ||
980 | |||
981 | /* reset list */ | ||
982 | layer->state = MXR_LAYER_STREAMING_FINISH; | ||
983 | |||
984 | /* set all buffer to be done */ | ||
985 | list_for_each_entry_safe(buf, buf_tmp, &layer->enq_list, list) { | ||
986 | list_del(&buf->list); | ||
987 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
988 | } | ||
989 | |||
990 | spin_unlock_irqrestore(&layer->enq_slock, flags); | ||
991 | |||
992 | /* give 1 seconds to complete to complete last buffers */ | ||
993 | setup_timer_on_stack(&watchdog, mxr_watchdog, | ||
994 | (unsigned long)layer); | ||
995 | mod_timer(&watchdog, jiffies + msecs_to_jiffies(1000)); | ||
996 | |||
997 | /* wait until all buffers are goes to done state */ | ||
998 | vb2_wait_for_all_buffers(vq); | ||
999 | |||
1000 | /* stop timer if all synchronization is done */ | ||
1001 | del_timer_sync(&watchdog); | ||
1002 | destroy_timer_on_stack(&watchdog); | ||
1003 | |||
1004 | /* stopping hardware */ | ||
1005 | spin_lock_irqsave(&layer->enq_slock, flags); | ||
1006 | layer->state = MXR_LAYER_IDLE; | ||
1007 | spin_unlock_irqrestore(&layer->enq_slock, flags); | ||
1008 | |||
1009 | /* disabling layer in hardware */ | ||
1010 | layer->ops.stream_set(layer, MXR_DISABLE); | ||
1011 | /* remove one streamer */ | ||
1012 | mxr_streamer_put(mdev); | ||
1013 | /* allow changes in output configuration */ | ||
1014 | mxr_output_put(mdev); | ||
1015 | } | ||
1016 | |||
1017 | static struct vb2_ops mxr_video_qops = { | ||
1018 | .queue_setup = queue_setup, | ||
1019 | .buf_queue = buf_queue, | ||
1020 | .wait_prepare = vb2_ops_wait_prepare, | ||
1021 | .wait_finish = vb2_ops_wait_finish, | ||
1022 | .start_streaming = start_streaming, | ||
1023 | .stop_streaming = stop_streaming, | ||
1024 | }; | ||
1025 | |||
1026 | /* FIXME: try to put this functions to mxr_base_layer_create */ | ||
1027 | int mxr_base_layer_register(struct mxr_layer *layer) | ||
1028 | { | ||
1029 | struct mxr_device *mdev = layer->mdev; | ||
1030 | int ret; | ||
1031 | |||
1032 | ret = video_register_device(&layer->vfd, VFL_TYPE_GRABBER, -1); | ||
1033 | if (ret) | ||
1034 | mxr_err(mdev, "failed to register video device\n"); | ||
1035 | else | ||
1036 | mxr_info(mdev, "registered layer %s as /dev/video%d\n", | ||
1037 | layer->vfd.name, layer->vfd.num); | ||
1038 | return ret; | ||
1039 | } | ||
1040 | |||
1041 | void mxr_base_layer_unregister(struct mxr_layer *layer) | ||
1042 | { | ||
1043 | video_unregister_device(&layer->vfd); | ||
1044 | } | ||
1045 | |||
1046 | void mxr_layer_release(struct mxr_layer *layer) | ||
1047 | { | ||
1048 | if (layer->ops.release) | ||
1049 | layer->ops.release(layer); | ||
1050 | } | ||
1051 | |||
1052 | void mxr_base_layer_release(struct mxr_layer *layer) | ||
1053 | { | ||
1054 | kfree(layer); | ||
1055 | } | ||
1056 | |||
1057 | static void mxr_vfd_release(struct video_device *vdev) | ||
1058 | { | ||
1059 | pr_info("video device release\n"); | ||
1060 | } | ||
1061 | |||
1062 | struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, | ||
1063 | int idx, char *name, const struct mxr_layer_ops *ops) | ||
1064 | { | ||
1065 | struct mxr_layer *layer; | ||
1066 | |||
1067 | layer = kzalloc(sizeof(*layer), GFP_KERNEL); | ||
1068 | if (layer == NULL) { | ||
1069 | mxr_err(mdev, "not enough memory for layer.\n"); | ||
1070 | goto fail; | ||
1071 | } | ||
1072 | |||
1073 | layer->mdev = mdev; | ||
1074 | layer->idx = idx; | ||
1075 | layer->ops = *ops; | ||
1076 | |||
1077 | spin_lock_init(&layer->enq_slock); | ||
1078 | INIT_LIST_HEAD(&layer->enq_list); | ||
1079 | mutex_init(&layer->mutex); | ||
1080 | |||
1081 | layer->vfd = (struct video_device) { | ||
1082 | .minor = -1, | ||
1083 | .release = mxr_vfd_release, | ||
1084 | .fops = &mxr_fops, | ||
1085 | .vfl_dir = VFL_DIR_TX, | ||
1086 | .ioctl_ops = &mxr_ioctl_ops, | ||
1087 | }; | ||
1088 | strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name)); | ||
1089 | |||
1090 | video_set_drvdata(&layer->vfd, layer); | ||
1091 | layer->vfd.lock = &layer->mutex; | ||
1092 | layer->vfd.v4l2_dev = &mdev->v4l2_dev; | ||
1093 | |||
1094 | layer->vb_queue = (struct vb2_queue) { | ||
1095 | .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, | ||
1096 | .io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF, | ||
1097 | .drv_priv = layer, | ||
1098 | .buf_struct_size = sizeof(struct mxr_buffer), | ||
1099 | .ops = &mxr_video_qops, | ||
1100 | .min_buffers_needed = 1, | ||
1101 | .mem_ops = &vb2_dma_contig_memops, | ||
1102 | .lock = &layer->mutex, | ||
1103 | .dev = mdev->dev, | ||
1104 | }; | ||
1105 | |||
1106 | return layer; | ||
1107 | |||
1108 | fail: | ||
1109 | return NULL; | ||
1110 | } | ||
1111 | |||
1112 | static const struct mxr_format *find_format_by_fourcc( | ||
1113 | struct mxr_layer *layer, unsigned long fourcc) | ||
1114 | { | ||
1115 | int i; | ||
1116 | |||
1117 | for (i = 0; i < layer->fmt_array_size; ++i) | ||
1118 | if (layer->fmt_array[i]->fourcc == fourcc) | ||
1119 | return layer->fmt_array[i]; | ||
1120 | return NULL; | ||
1121 | } | ||
1122 | |||
1123 | static const struct mxr_format *find_format_by_index( | ||
1124 | struct mxr_layer *layer, unsigned long index) | ||
1125 | { | ||
1126 | if (index >= layer->fmt_array_size) | ||
1127 | return NULL; | ||
1128 | return layer->fmt_array[index]; | ||
1129 | } | ||
1130 | |||
diff --git a/drivers/media/platform/s5p-tv/mixer_vp_layer.c b/drivers/media/platform/s5p-tv/mixer_vp_layer.c deleted file mode 100644 index 6fa6f673f53b..000000000000 --- a/drivers/media/platform/s5p-tv/mixer_vp_layer.c +++ /dev/null | |||
@@ -1,242 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung TV Mixer driver | ||
3 | * | ||
4 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
5 | * | ||
6 | * Tomasz Stanislawski, <t.stanislaws@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 as published | ||
10 | * by the Free Software Foundiation. either version 2 of the License, | ||
11 | * or (at your option) any later version | ||
12 | */ | ||
13 | |||
14 | #include "mixer.h" | ||
15 | |||
16 | #include "regs-vp.h" | ||
17 | |||
18 | #include <media/videobuf2-dma-contig.h> | ||
19 | |||
20 | /* FORMAT DEFINITIONS */ | ||
21 | static const struct mxr_format mxr_fmt_nv12 = { | ||
22 | .name = "NV12", | ||
23 | .fourcc = V4L2_PIX_FMT_NV12, | ||
24 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
25 | .num_planes = 2, | ||
26 | .plane = { | ||
27 | { .width = 1, .height = 1, .size = 1 }, | ||
28 | { .width = 2, .height = 2, .size = 2 }, | ||
29 | }, | ||
30 | .num_subframes = 1, | ||
31 | .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR, | ||
32 | }; | ||
33 | |||
34 | static const struct mxr_format mxr_fmt_nv21 = { | ||
35 | .name = "NV21", | ||
36 | .fourcc = V4L2_PIX_FMT_NV21, | ||
37 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
38 | .num_planes = 2, | ||
39 | .plane = { | ||
40 | { .width = 1, .height = 1, .size = 1 }, | ||
41 | { .width = 2, .height = 2, .size = 2 }, | ||
42 | }, | ||
43 | .num_subframes = 1, | ||
44 | .cookie = VP_MODE_NV21 | VP_MODE_MEM_LINEAR, | ||
45 | }; | ||
46 | |||
47 | static const struct mxr_format mxr_fmt_nv12m = { | ||
48 | .name = "NV12 (mplane)", | ||
49 | .fourcc = V4L2_PIX_FMT_NV12M, | ||
50 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
51 | .num_planes = 2, | ||
52 | .plane = { | ||
53 | { .width = 1, .height = 1, .size = 1 }, | ||
54 | { .width = 2, .height = 2, .size = 2 }, | ||
55 | }, | ||
56 | .num_subframes = 2, | ||
57 | .plane2subframe = {0, 1}, | ||
58 | .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR, | ||
59 | }; | ||
60 | |||
61 | static const struct mxr_format mxr_fmt_nv12mt = { | ||
62 | .name = "NV12 tiled (mplane)", | ||
63 | .fourcc = V4L2_PIX_FMT_NV12MT, | ||
64 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
65 | .num_planes = 2, | ||
66 | .plane = { | ||
67 | { .width = 128, .height = 32, .size = 4096 }, | ||
68 | { .width = 128, .height = 32, .size = 2048 }, | ||
69 | }, | ||
70 | .num_subframes = 2, | ||
71 | .plane2subframe = {0, 1}, | ||
72 | .cookie = VP_MODE_NV12 | VP_MODE_MEM_TILED, | ||
73 | }; | ||
74 | |||
75 | static const struct mxr_format *mxr_video_format[] = { | ||
76 | &mxr_fmt_nv12, | ||
77 | &mxr_fmt_nv21, | ||
78 | &mxr_fmt_nv12m, | ||
79 | &mxr_fmt_nv12mt, | ||
80 | }; | ||
81 | |||
82 | /* AUXILIARY CALLBACKS */ | ||
83 | |||
84 | static void mxr_vp_layer_release(struct mxr_layer *layer) | ||
85 | { | ||
86 | mxr_base_layer_unregister(layer); | ||
87 | mxr_base_layer_release(layer); | ||
88 | } | ||
89 | |||
90 | static void mxr_vp_buffer_set(struct mxr_layer *layer, | ||
91 | struct mxr_buffer *buf) | ||
92 | { | ||
93 | dma_addr_t luma_addr[2] = {0, 0}; | ||
94 | dma_addr_t chroma_addr[2] = {0, 0}; | ||
95 | |||
96 | if (buf == NULL) { | ||
97 | mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr); | ||
98 | return; | ||
99 | } | ||
100 | luma_addr[0] = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); | ||
101 | if (layer->fmt->num_subframes == 2) { | ||
102 | chroma_addr[0] = | ||
103 | vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); | ||
104 | } else { | ||
105 | /* FIXME: mxr_get_plane_size compute integer division, | ||
106 | * which is slow and should not be performed in interrupt */ | ||
107 | chroma_addr[0] = luma_addr[0] + mxr_get_plane_size( | ||
108 | &layer->fmt->plane[0], layer->geo.src.full_width, | ||
109 | layer->geo.src.full_height); | ||
110 | } | ||
111 | if (layer->fmt->cookie & VP_MODE_MEM_TILED) { | ||
112 | luma_addr[1] = luma_addr[0] + 0x40; | ||
113 | chroma_addr[1] = chroma_addr[0] + 0x40; | ||
114 | } else { | ||
115 | luma_addr[1] = luma_addr[0] + layer->geo.src.full_width; | ||
116 | chroma_addr[1] = chroma_addr[0]; | ||
117 | } | ||
118 | mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr); | ||
119 | } | ||
120 | |||
121 | static void mxr_vp_stream_set(struct mxr_layer *layer, int en) | ||
122 | { | ||
123 | mxr_reg_vp_layer_stream(layer->mdev, en); | ||
124 | } | ||
125 | |||
126 | static void mxr_vp_format_set(struct mxr_layer *layer) | ||
127 | { | ||
128 | mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo); | ||
129 | } | ||
130 | |||
131 | static inline unsigned int do_center(unsigned int center, | ||
132 | unsigned int size, unsigned int upper, unsigned int flags) | ||
133 | { | ||
134 | unsigned int lower; | ||
135 | |||
136 | if (flags & MXR_NO_OFFSET) | ||
137 | return 0; | ||
138 | |||
139 | lower = center - min(center, size / 2); | ||
140 | return min(lower, upper - size); | ||
141 | } | ||
142 | |||
143 | static void mxr_vp_fix_geometry(struct mxr_layer *layer, | ||
144 | enum mxr_geometry_stage stage, unsigned long flags) | ||
145 | { | ||
146 | struct mxr_geometry *geo = &layer->geo; | ||
147 | struct mxr_crop *src = &geo->src; | ||
148 | struct mxr_crop *dst = &geo->dst; | ||
149 | unsigned long x_center, y_center; | ||
150 | |||
151 | switch (stage) { | ||
152 | |||
153 | case MXR_GEOMETRY_SINK: /* nothing to be fixed here */ | ||
154 | case MXR_GEOMETRY_COMPOSE: | ||
155 | /* remember center of the area */ | ||
156 | x_center = dst->x_offset + dst->width / 2; | ||
157 | y_center = dst->y_offset + dst->height / 2; | ||
158 | |||
159 | /* ensure that compose is reachable using 16x scaling */ | ||
160 | dst->width = clamp(dst->width, 8U, 16 * src->full_width); | ||
161 | dst->height = clamp(dst->height, 1U, 16 * src->full_height); | ||
162 | |||
163 | /* setup offsets */ | ||
164 | dst->x_offset = do_center(x_center, dst->width, | ||
165 | dst->full_width, flags); | ||
166 | dst->y_offset = do_center(y_center, dst->height, | ||
167 | dst->full_height, flags); | ||
168 | flags = 0; /* remove possible MXR_NO_OFFSET flag */ | ||
169 | /* fall through */ | ||
170 | case MXR_GEOMETRY_CROP: | ||
171 | /* remember center of the area */ | ||
172 | x_center = src->x_offset + src->width / 2; | ||
173 | y_center = src->y_offset + src->height / 2; | ||
174 | |||
175 | /* ensure scaling is between 0.25x .. 16x */ | ||
176 | src->width = clamp(src->width, round_up(dst->width / 16, 4), | ||
177 | dst->width * 4); | ||
178 | src->height = clamp(src->height, round_up(dst->height / 16, 4), | ||
179 | dst->height * 4); | ||
180 | |||
181 | /* hardware limits */ | ||
182 | src->width = clamp(src->width, 32U, 2047U); | ||
183 | src->height = clamp(src->height, 4U, 2047U); | ||
184 | |||
185 | /* setup offsets */ | ||
186 | src->x_offset = do_center(x_center, src->width, | ||
187 | src->full_width, flags); | ||
188 | src->y_offset = do_center(y_center, src->height, | ||
189 | src->full_height, flags); | ||
190 | |||
191 | /* setting scaling ratio */ | ||
192 | geo->x_ratio = (src->width << 16) / dst->width; | ||
193 | geo->y_ratio = (src->height << 16) / dst->height; | ||
194 | /* fall through */ | ||
195 | |||
196 | case MXR_GEOMETRY_SOURCE: | ||
197 | src->full_width = clamp(src->full_width, | ||
198 | ALIGN(src->width + src->x_offset, 8), 8192U); | ||
199 | src->full_height = clamp(src->full_height, | ||
200 | src->height + src->y_offset, 8192U); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | /* PUBLIC API */ | ||
205 | |||
206 | struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx) | ||
207 | { | ||
208 | struct mxr_layer *layer; | ||
209 | int ret; | ||
210 | const struct mxr_layer_ops ops = { | ||
211 | .release = mxr_vp_layer_release, | ||
212 | .buffer_set = mxr_vp_buffer_set, | ||
213 | .stream_set = mxr_vp_stream_set, | ||
214 | .format_set = mxr_vp_format_set, | ||
215 | .fix_geometry = mxr_vp_fix_geometry, | ||
216 | }; | ||
217 | char name[32]; | ||
218 | |||
219 | sprintf(name, "video%d", idx); | ||
220 | |||
221 | layer = mxr_base_layer_create(mdev, idx, name, &ops); | ||
222 | if (layer == NULL) { | ||
223 | mxr_err(mdev, "failed to initialize layer(%d) base\n", idx); | ||
224 | goto fail; | ||
225 | } | ||
226 | |||
227 | layer->fmt_array = mxr_video_format; | ||
228 | layer->fmt_array_size = ARRAY_SIZE(mxr_video_format); | ||
229 | |||
230 | ret = mxr_base_layer_register(layer); | ||
231 | if (ret) | ||
232 | goto fail_layer; | ||
233 | |||
234 | return layer; | ||
235 | |||
236 | fail_layer: | ||
237 | mxr_base_layer_release(layer); | ||
238 | |||
239 | fail: | ||
240 | return NULL; | ||
241 | } | ||
242 | |||
diff --git a/drivers/media/platform/s5p-tv/regs-hdmi.h b/drivers/media/platform/s5p-tv/regs-hdmi.h deleted file mode 100644 index a889d1f57f28..000000000000 --- a/drivers/media/platform/s5p-tv/regs-hdmi.h +++ /dev/null | |||
@@ -1,146 +0,0 @@ | |||
1 | /* linux/arch/arm/mach-exynos4/include/mach/regs-hdmi.h | ||
2 | * | ||
3 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com/ | ||
5 | * | ||
6 | * HDMI register header file for Samsung TVOUT driver | ||
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 SAMSUNG_REGS_HDMI_H | ||
14 | #define SAMSUNG_REGS_HDMI_H | ||
15 | |||
16 | /* | ||
17 | * Register part | ||
18 | */ | ||
19 | |||
20 | #define HDMI_CTRL_BASE(x) ((x) + 0x00000000) | ||
21 | #define HDMI_CORE_BASE(x) ((x) + 0x00010000) | ||
22 | #define HDMI_TG_BASE(x) ((x) + 0x00050000) | ||
23 | |||
24 | /* Control registers */ | ||
25 | #define HDMI_INTC_CON HDMI_CTRL_BASE(0x0000) | ||
26 | #define HDMI_INTC_FLAG HDMI_CTRL_BASE(0x0004) | ||
27 | #define HDMI_HPD_STATUS HDMI_CTRL_BASE(0x000C) | ||
28 | #define HDMI_PHY_RSTOUT HDMI_CTRL_BASE(0x0014) | ||
29 | #define HDMI_PHY_VPLL HDMI_CTRL_BASE(0x0018) | ||
30 | #define HDMI_PHY_CMU HDMI_CTRL_BASE(0x001C) | ||
31 | #define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0020) | ||
32 | |||
33 | /* Core registers */ | ||
34 | #define HDMI_CON_0 HDMI_CORE_BASE(0x0000) | ||
35 | #define HDMI_CON_1 HDMI_CORE_BASE(0x0004) | ||
36 | #define HDMI_CON_2 HDMI_CORE_BASE(0x0008) | ||
37 | #define HDMI_SYS_STATUS HDMI_CORE_BASE(0x0010) | ||
38 | #define HDMI_PHY_STATUS HDMI_CORE_BASE(0x0014) | ||
39 | #define HDMI_STATUS_EN HDMI_CORE_BASE(0x0020) | ||
40 | #define HDMI_HPD HDMI_CORE_BASE(0x0030) | ||
41 | #define HDMI_MODE_SEL HDMI_CORE_BASE(0x0040) | ||
42 | #define HDMI_BLUE_SCREEN_0 HDMI_CORE_BASE(0x0050) | ||
43 | #define HDMI_BLUE_SCREEN_1 HDMI_CORE_BASE(0x0054) | ||
44 | #define HDMI_BLUE_SCREEN_2 HDMI_CORE_BASE(0x0058) | ||
45 | #define HDMI_H_BLANK_0 HDMI_CORE_BASE(0x00A0) | ||
46 | #define HDMI_H_BLANK_1 HDMI_CORE_BASE(0x00A4) | ||
47 | #define HDMI_V_BLANK_0 HDMI_CORE_BASE(0x00B0) | ||
48 | #define HDMI_V_BLANK_1 HDMI_CORE_BASE(0x00B4) | ||
49 | #define HDMI_V_BLANK_2 HDMI_CORE_BASE(0x00B8) | ||
50 | #define HDMI_H_V_LINE_0 HDMI_CORE_BASE(0x00C0) | ||
51 | #define HDMI_H_V_LINE_1 HDMI_CORE_BASE(0x00C4) | ||
52 | #define HDMI_H_V_LINE_2 HDMI_CORE_BASE(0x00C8) | ||
53 | #define HDMI_VSYNC_POL HDMI_CORE_BASE(0x00E4) | ||
54 | #define HDMI_INT_PRO_MODE HDMI_CORE_BASE(0x00E8) | ||
55 | #define HDMI_V_BLANK_F_0 HDMI_CORE_BASE(0x0110) | ||
56 | #define HDMI_V_BLANK_F_1 HDMI_CORE_BASE(0x0114) | ||
57 | #define HDMI_V_BLANK_F_2 HDMI_CORE_BASE(0x0118) | ||
58 | #define HDMI_H_SYNC_GEN_0 HDMI_CORE_BASE(0x0120) | ||
59 | #define HDMI_H_SYNC_GEN_1 HDMI_CORE_BASE(0x0124) | ||
60 | #define HDMI_H_SYNC_GEN_2 HDMI_CORE_BASE(0x0128) | ||
61 | #define HDMI_V_SYNC_GEN_1_0 HDMI_CORE_BASE(0x0130) | ||
62 | #define HDMI_V_SYNC_GEN_1_1 HDMI_CORE_BASE(0x0134) | ||
63 | #define HDMI_V_SYNC_GEN_1_2 HDMI_CORE_BASE(0x0138) | ||
64 | #define HDMI_V_SYNC_GEN_2_0 HDMI_CORE_BASE(0x0140) | ||
65 | #define HDMI_V_SYNC_GEN_2_1 HDMI_CORE_BASE(0x0144) | ||
66 | #define HDMI_V_SYNC_GEN_2_2 HDMI_CORE_BASE(0x0148) | ||
67 | #define HDMI_V_SYNC_GEN_3_0 HDMI_CORE_BASE(0x0150) | ||
68 | #define HDMI_V_SYNC_GEN_3_1 HDMI_CORE_BASE(0x0154) | ||
69 | #define HDMI_V_SYNC_GEN_3_2 HDMI_CORE_BASE(0x0158) | ||
70 | #define HDMI_AVI_CON HDMI_CORE_BASE(0x0300) | ||
71 | #define HDMI_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n)) | ||
72 | #define HDMI_DC_CONTROL HDMI_CORE_BASE(0x05C0) | ||
73 | #define HDMI_VIDEO_PATTERN_GEN HDMI_CORE_BASE(0x05C4) | ||
74 | #define HDMI_HPD_GEN HDMI_CORE_BASE(0x05C8) | ||
75 | |||
76 | /* Timing generator registers */ | ||
77 | #define HDMI_TG_CMD HDMI_TG_BASE(0x0000) | ||
78 | #define HDMI_TG_H_FSZ_L HDMI_TG_BASE(0x0018) | ||
79 | #define HDMI_TG_H_FSZ_H HDMI_TG_BASE(0x001C) | ||
80 | #define HDMI_TG_HACT_ST_L HDMI_TG_BASE(0x0020) | ||
81 | #define HDMI_TG_HACT_ST_H HDMI_TG_BASE(0x0024) | ||
82 | #define HDMI_TG_HACT_SZ_L HDMI_TG_BASE(0x0028) | ||
83 | #define HDMI_TG_HACT_SZ_H HDMI_TG_BASE(0x002C) | ||
84 | #define HDMI_TG_V_FSZ_L HDMI_TG_BASE(0x0030) | ||
85 | #define HDMI_TG_V_FSZ_H HDMI_TG_BASE(0x0034) | ||
86 | #define HDMI_TG_VSYNC_L HDMI_TG_BASE(0x0038) | ||
87 | #define HDMI_TG_VSYNC_H HDMI_TG_BASE(0x003C) | ||
88 | #define HDMI_TG_VSYNC2_L HDMI_TG_BASE(0x0040) | ||
89 | #define HDMI_TG_VSYNC2_H HDMI_TG_BASE(0x0044) | ||
90 | #define HDMI_TG_VACT_ST_L HDMI_TG_BASE(0x0048) | ||
91 | #define HDMI_TG_VACT_ST_H HDMI_TG_BASE(0x004C) | ||
92 | #define HDMI_TG_VACT_SZ_L HDMI_TG_BASE(0x0050) | ||
93 | #define HDMI_TG_VACT_SZ_H HDMI_TG_BASE(0x0054) | ||
94 | #define HDMI_TG_FIELD_CHG_L HDMI_TG_BASE(0x0058) | ||
95 | #define HDMI_TG_FIELD_CHG_H HDMI_TG_BASE(0x005C) | ||
96 | #define HDMI_TG_VACT_ST2_L HDMI_TG_BASE(0x0060) | ||
97 | #define HDMI_TG_VACT_ST2_H HDMI_TG_BASE(0x0064) | ||
98 | #define HDMI_TG_VSYNC_TOP_HDMI_L HDMI_TG_BASE(0x0078) | ||
99 | #define HDMI_TG_VSYNC_TOP_HDMI_H HDMI_TG_BASE(0x007C) | ||
100 | #define HDMI_TG_VSYNC_BOT_HDMI_L HDMI_TG_BASE(0x0080) | ||
101 | #define HDMI_TG_VSYNC_BOT_HDMI_H HDMI_TG_BASE(0x0084) | ||
102 | #define HDMI_TG_FIELD_TOP_HDMI_L HDMI_TG_BASE(0x0088) | ||
103 | #define HDMI_TG_FIELD_TOP_HDMI_H HDMI_TG_BASE(0x008C) | ||
104 | #define HDMI_TG_FIELD_BOT_HDMI_L HDMI_TG_BASE(0x0090) | ||
105 | #define HDMI_TG_FIELD_BOT_HDMI_H HDMI_TG_BASE(0x0094) | ||
106 | |||
107 | /* | ||
108 | * Bit definition part | ||
109 | */ | ||
110 | |||
111 | /* HDMI_INTC_CON */ | ||
112 | #define HDMI_INTC_EN_GLOBAL (1 << 6) | ||
113 | #define HDMI_INTC_EN_HPD_PLUG (1 << 3) | ||
114 | #define HDMI_INTC_EN_HPD_UNPLUG (1 << 2) | ||
115 | |||
116 | /* HDMI_INTC_FLAG */ | ||
117 | #define HDMI_INTC_FLAG_HPD_PLUG (1 << 3) | ||
118 | #define HDMI_INTC_FLAG_HPD_UNPLUG (1 << 2) | ||
119 | |||
120 | /* HDMI_PHY_RSTOUT */ | ||
121 | #define HDMI_PHY_SW_RSTOUT (1 << 0) | ||
122 | |||
123 | /* HDMI_CORE_RSTOUT */ | ||
124 | #define HDMI_CORE_SW_RSTOUT (1 << 0) | ||
125 | |||
126 | /* HDMI_CON_0 */ | ||
127 | #define HDMI_BLUE_SCR_EN (1 << 5) | ||
128 | #define HDMI_EN (1 << 0) | ||
129 | |||
130 | /* HDMI_CON_2 */ | ||
131 | #define HDMI_DVI_PERAMBLE_EN (1 << 5) | ||
132 | #define HDMI_DVI_BAND_EN (1 << 1) | ||
133 | |||
134 | /* HDMI_PHY_STATUS */ | ||
135 | #define HDMI_PHY_STATUS_READY (1 << 0) | ||
136 | |||
137 | /* HDMI_MODE_SEL */ | ||
138 | #define HDMI_MODE_HDMI_EN (1 << 1) | ||
139 | #define HDMI_MODE_DVI_EN (1 << 0) | ||
140 | #define HDMI_MODE_MASK (3 << 0) | ||
141 | |||
142 | /* HDMI_TG_CMD */ | ||
143 | #define HDMI_TG_FIELD_EN (1 << 1) | ||
144 | #define HDMI_TG_EN (1 << 0) | ||
145 | |||
146 | #endif /* SAMSUNG_REGS_HDMI_H */ | ||
diff --git a/drivers/media/platform/s5p-tv/regs-mixer.h b/drivers/media/platform/s5p-tv/regs-mixer.h deleted file mode 100644 index 158abb43d0a4..000000000000 --- a/drivers/media/platform/s5p-tv/regs-mixer.h +++ /dev/null | |||
@@ -1,122 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
3 | * http://www.samsung.com/ | ||
4 | * | ||
5 | * Mixer register header file for Samsung Mixer driver | ||
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 version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #ifndef SAMSUNG_REGS_MIXER_H | ||
12 | #define SAMSUNG_REGS_MIXER_H | ||
13 | |||
14 | /* | ||
15 | * Register part | ||
16 | */ | ||
17 | #define MXR_STATUS 0x0000 | ||
18 | #define MXR_CFG 0x0004 | ||
19 | #define MXR_INT_EN 0x0008 | ||
20 | #define MXR_INT_STATUS 0x000C | ||
21 | #define MXR_LAYER_CFG 0x0010 | ||
22 | #define MXR_VIDEO_CFG 0x0014 | ||
23 | #define MXR_GRAPHIC0_CFG 0x0020 | ||
24 | #define MXR_GRAPHIC0_BASE 0x0024 | ||
25 | #define MXR_GRAPHIC0_SPAN 0x0028 | ||
26 | #define MXR_GRAPHIC0_SXY 0x002C | ||
27 | #define MXR_GRAPHIC0_WH 0x0030 | ||
28 | #define MXR_GRAPHIC0_DXY 0x0034 | ||
29 | #define MXR_GRAPHIC0_BLANK 0x0038 | ||
30 | #define MXR_GRAPHIC1_CFG 0x0040 | ||
31 | #define MXR_GRAPHIC1_BASE 0x0044 | ||
32 | #define MXR_GRAPHIC1_SPAN 0x0048 | ||
33 | #define MXR_GRAPHIC1_SXY 0x004C | ||
34 | #define MXR_GRAPHIC1_WH 0x0050 | ||
35 | #define MXR_GRAPHIC1_DXY 0x0054 | ||
36 | #define MXR_GRAPHIC1_BLANK 0x0058 | ||
37 | #define MXR_BG_CFG 0x0060 | ||
38 | #define MXR_BG_COLOR0 0x0064 | ||
39 | #define MXR_BG_COLOR1 0x0068 | ||
40 | #define MXR_BG_COLOR2 0x006C | ||
41 | |||
42 | /* for parametrized access to layer registers */ | ||
43 | #define MXR_GRAPHIC_CFG(i) (0x0020 + (i) * 0x20) | ||
44 | #define MXR_GRAPHIC_BASE(i) (0x0024 + (i) * 0x20) | ||
45 | #define MXR_GRAPHIC_SPAN(i) (0x0028 + (i) * 0x20) | ||
46 | #define MXR_GRAPHIC_SXY(i) (0x002C + (i) * 0x20) | ||
47 | #define MXR_GRAPHIC_WH(i) (0x0030 + (i) * 0x20) | ||
48 | #define MXR_GRAPHIC_DXY(i) (0x0034 + (i) * 0x20) | ||
49 | |||
50 | /* | ||
51 | * Bit definition part | ||
52 | */ | ||
53 | |||
54 | /* generates mask for range of bits */ | ||
55 | #define MXR_MASK(high_bit, low_bit) \ | ||
56 | (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit)) | ||
57 | |||
58 | #define MXR_MASK_VAL(val, high_bit, low_bit) \ | ||
59 | (((val) << (low_bit)) & MXR_MASK(high_bit, low_bit)) | ||
60 | |||
61 | /* bits for MXR_STATUS */ | ||
62 | #define MXR_STATUS_16_BURST (1 << 7) | ||
63 | #define MXR_STATUS_BURST_MASK (1 << 7) | ||
64 | #define MXR_STATUS_SYNC_ENABLE (1 << 2) | ||
65 | #define MXR_STATUS_REG_RUN (1 << 0) | ||
66 | |||
67 | /* bits for MXR_CFG */ | ||
68 | #define MXR_CFG_OUT_YUV444 (0 << 8) | ||
69 | #define MXR_CFG_OUT_RGB888 (1 << 8) | ||
70 | #define MXR_CFG_OUT_MASK (1 << 8) | ||
71 | #define MXR_CFG_DST_SDO (0 << 7) | ||
72 | #define MXR_CFG_DST_HDMI (1 << 7) | ||
73 | #define MXR_CFG_DST_MASK (1 << 7) | ||
74 | #define MXR_CFG_SCAN_HD_720 (0 << 6) | ||
75 | #define MXR_CFG_SCAN_HD_1080 (1 << 6) | ||
76 | #define MXR_CFG_GRP1_ENABLE (1 << 5) | ||
77 | #define MXR_CFG_GRP0_ENABLE (1 << 4) | ||
78 | #define MXR_CFG_VP_ENABLE (1 << 3) | ||
79 | #define MXR_CFG_SCAN_INTERLACE (0 << 2) | ||
80 | #define MXR_CFG_SCAN_PROGRASSIVE (1 << 2) | ||
81 | #define MXR_CFG_SCAN_NTSC (0 << 1) | ||
82 | #define MXR_CFG_SCAN_PAL (1 << 1) | ||
83 | #define MXR_CFG_SCAN_SD (0 << 0) | ||
84 | #define MXR_CFG_SCAN_HD (1 << 0) | ||
85 | #define MXR_CFG_SCAN_MASK 0x47 | ||
86 | |||
87 | /* bits for MXR_GRAPHICn_CFG */ | ||
88 | #define MXR_GRP_CFG_COLOR_KEY_DISABLE (1 << 21) | ||
89 | #define MXR_GRP_CFG_BLEND_PRE_MUL (1 << 20) | ||
90 | #define MXR_GRP_CFG_FORMAT_VAL(x) MXR_MASK_VAL(x, 11, 8) | ||
91 | #define MXR_GRP_CFG_FORMAT_MASK MXR_GRP_CFG_FORMAT_VAL(~0) | ||
92 | #define MXR_GRP_CFG_ALPHA_VAL(x) MXR_MASK_VAL(x, 7, 0) | ||
93 | |||
94 | /* bits for MXR_GRAPHICn_WH */ | ||
95 | #define MXR_GRP_WH_H_SCALE(x) MXR_MASK_VAL(x, 28, 28) | ||
96 | #define MXR_GRP_WH_V_SCALE(x) MXR_MASK_VAL(x, 12, 12) | ||
97 | #define MXR_GRP_WH_WIDTH(x) MXR_MASK_VAL(x, 26, 16) | ||
98 | #define MXR_GRP_WH_HEIGHT(x) MXR_MASK_VAL(x, 10, 0) | ||
99 | |||
100 | /* bits for MXR_GRAPHICn_SXY */ | ||
101 | #define MXR_GRP_SXY_SX(x) MXR_MASK_VAL(x, 26, 16) | ||
102 | #define MXR_GRP_SXY_SY(x) MXR_MASK_VAL(x, 10, 0) | ||
103 | |||
104 | /* bits for MXR_GRAPHICn_DXY */ | ||
105 | #define MXR_GRP_DXY_DX(x) MXR_MASK_VAL(x, 26, 16) | ||
106 | #define MXR_GRP_DXY_DY(x) MXR_MASK_VAL(x, 10, 0) | ||
107 | |||
108 | /* bits for MXR_INT_EN */ | ||
109 | #define MXR_INT_EN_VSYNC (1 << 11) | ||
110 | #define MXR_INT_EN_ALL (0x0f << 8) | ||
111 | |||
112 | /* bit for MXR_INT_STATUS */ | ||
113 | #define MXR_INT_CLEAR_VSYNC (1 << 11) | ||
114 | #define MXR_INT_STATUS_VSYNC (1 << 0) | ||
115 | |||
116 | /* bit for MXR_LAYER_CFG */ | ||
117 | #define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8) | ||
118 | #define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4) | ||
119 | #define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0) | ||
120 | |||
121 | #endif /* SAMSUNG_REGS_MIXER_H */ | ||
122 | |||
diff --git a/drivers/media/platform/s5p-tv/regs-sdo.h b/drivers/media/platform/s5p-tv/regs-sdo.h deleted file mode 100644 index 6f22fbfe2f6c..000000000000 --- a/drivers/media/platform/s5p-tv/regs-sdo.h +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
1 | /* drivers/media/platform/s5p-tv/regs-sdo.h | ||
2 | * | ||
3 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com/ | ||
5 | * | ||
6 | * SDO register description file | ||
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 SAMSUNG_REGS_SDO_H | ||
14 | #define SAMSUNG_REGS_SDO_H | ||
15 | |||
16 | /* | ||
17 | * Register part | ||
18 | */ | ||
19 | |||
20 | #define SDO_CLKCON 0x0000 | ||
21 | #define SDO_CONFIG 0x0008 | ||
22 | #define SDO_VBI 0x0014 | ||
23 | #define SDO_DAC 0x003C | ||
24 | #define SDO_CCCON 0x0180 | ||
25 | #define SDO_IRQ 0x0280 | ||
26 | #define SDO_IRQMASK 0x0284 | ||
27 | #define SDO_VERSION 0x03D8 | ||
28 | |||
29 | /* | ||
30 | * Bit definition part | ||
31 | */ | ||
32 | |||
33 | /* SDO Clock Control Register (SDO_CLKCON) */ | ||
34 | #define SDO_TVOUT_SW_RESET (1 << 4) | ||
35 | #define SDO_TVOUT_CLOCK_READY (1 << 1) | ||
36 | #define SDO_TVOUT_CLOCK_ON (1 << 0) | ||
37 | |||
38 | /* SDO Video Standard Configuration Register (SDO_CONFIG) */ | ||
39 | #define SDO_PROGRESSIVE (1 << 4) | ||
40 | #define SDO_NTSC_M 0 | ||
41 | #define SDO_PAL_M 1 | ||
42 | #define SDO_PAL_BGHID 2 | ||
43 | #define SDO_PAL_N 3 | ||
44 | #define SDO_PAL_NC 4 | ||
45 | #define SDO_NTSC_443 8 | ||
46 | #define SDO_PAL_60 9 | ||
47 | #define SDO_STANDARD_MASK 0xf | ||
48 | |||
49 | /* SDO VBI Configuration Register (SDO_VBI) */ | ||
50 | #define SDO_CVBS_WSS_INS (1 << 14) | ||
51 | #define SDO_CVBS_CLOSED_CAPTION_MASK (3 << 12) | ||
52 | |||
53 | /* SDO DAC Configuration Register (SDO_DAC) */ | ||
54 | #define SDO_POWER_ON_DAC (1 << 0) | ||
55 | |||
56 | /* SDO Color Compensation On/Off Control (SDO_CCCON) */ | ||
57 | #define SDO_COMPENSATION_BHS_ADJ_OFF (1 << 4) | ||
58 | #define SDO_COMPENSATION_CVBS_COMP_OFF (1 << 0) | ||
59 | |||
60 | /* SDO Interrupt Request Register (SDO_IRQ) */ | ||
61 | #define SDO_VSYNC_IRQ_PEND (1 << 0) | ||
62 | |||
63 | #endif /* SAMSUNG_REGS_SDO_H */ | ||
diff --git a/drivers/media/platform/s5p-tv/regs-vp.h b/drivers/media/platform/s5p-tv/regs-vp.h deleted file mode 100644 index 6c63984e11e8..000000000000 --- a/drivers/media/platform/s5p-tv/regs-vp.h +++ /dev/null | |||
@@ -1,88 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
3 | * http://www.samsung.com/ | ||
4 | * | ||
5 | * Video processor register header file for Samsung Mixer driver | ||
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 version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef SAMSUNG_REGS_VP_H | ||
13 | #define SAMSUNG_REGS_VP_H | ||
14 | |||
15 | /* | ||
16 | * Register part | ||
17 | */ | ||
18 | |||
19 | #define VP_ENABLE 0x0000 | ||
20 | #define VP_SRESET 0x0004 | ||
21 | #define VP_SHADOW_UPDATE 0x0008 | ||
22 | #define VP_FIELD_ID 0x000C | ||
23 | #define VP_MODE 0x0010 | ||
24 | #define VP_IMG_SIZE_Y 0x0014 | ||
25 | #define VP_IMG_SIZE_C 0x0018 | ||
26 | #define VP_PER_RATE_CTRL 0x001C | ||
27 | #define VP_TOP_Y_PTR 0x0028 | ||
28 | #define VP_BOT_Y_PTR 0x002C | ||
29 | #define VP_TOP_C_PTR 0x0030 | ||
30 | #define VP_BOT_C_PTR 0x0034 | ||
31 | #define VP_ENDIAN_MODE 0x03CC | ||
32 | #define VP_SRC_H_POSITION 0x0044 | ||
33 | #define VP_SRC_V_POSITION 0x0048 | ||
34 | #define VP_SRC_WIDTH 0x004C | ||
35 | #define VP_SRC_HEIGHT 0x0050 | ||
36 | #define VP_DST_H_POSITION 0x0054 | ||
37 | #define VP_DST_V_POSITION 0x0058 | ||
38 | #define VP_DST_WIDTH 0x005C | ||
39 | #define VP_DST_HEIGHT 0x0060 | ||
40 | #define VP_H_RATIO 0x0064 | ||
41 | #define VP_V_RATIO 0x0068 | ||
42 | #define VP_POLY8_Y0_LL 0x006C | ||
43 | #define VP_POLY4_Y0_LL 0x00EC | ||
44 | #define VP_POLY4_C0_LL 0x012C | ||
45 | |||
46 | /* | ||
47 | * Bit definition part | ||
48 | */ | ||
49 | |||
50 | /* generates mask for range of bits */ | ||
51 | |||
52 | #define VP_MASK(high_bit, low_bit) \ | ||
53 | (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit)) | ||
54 | |||
55 | #define VP_MASK_VAL(val, high_bit, low_bit) \ | ||
56 | (((val) << (low_bit)) & VP_MASK(high_bit, low_bit)) | ||
57 | |||
58 | /* VP_ENABLE */ | ||
59 | #define VP_ENABLE_ON (1 << 0) | ||
60 | |||
61 | /* VP_SRESET */ | ||
62 | #define VP_SRESET_PROCESSING (1 << 0) | ||
63 | |||
64 | /* VP_SHADOW_UPDATE */ | ||
65 | #define VP_SHADOW_UPDATE_ENABLE (1 << 0) | ||
66 | |||
67 | /* VP_MODE */ | ||
68 | #define VP_MODE_NV12 (0 << 6) | ||
69 | #define VP_MODE_NV21 (1 << 6) | ||
70 | #define VP_MODE_LINE_SKIP (1 << 5) | ||
71 | #define VP_MODE_MEM_LINEAR (0 << 4) | ||
72 | #define VP_MODE_MEM_TILED (1 << 4) | ||
73 | #define VP_MODE_FMT_MASK (5 << 4) | ||
74 | #define VP_MODE_FIELD_ID_AUTO_TOGGLING (1 << 2) | ||
75 | #define VP_MODE_2D_IPC (1 << 1) | ||
76 | |||
77 | /* VP_IMG_SIZE_Y */ | ||
78 | /* VP_IMG_SIZE_C */ | ||
79 | #define VP_IMG_HSIZE(x) VP_MASK_VAL(x, 29, 16) | ||
80 | #define VP_IMG_VSIZE(x) VP_MASK_VAL(x, 13, 0) | ||
81 | |||
82 | /* VP_SRC_H_POSITION */ | ||
83 | #define VP_SRC_H_POSITION_VAL(x) VP_MASK_VAL(x, 14, 4) | ||
84 | |||
85 | /* VP_ENDIAN_MODE */ | ||
86 | #define VP_ENDIAN_MODE_LITTLE (1 << 0) | ||
87 | |||
88 | #endif /* SAMSUNG_REGS_VP_H */ | ||
diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c deleted file mode 100644 index c75d4354d182..000000000000 --- a/drivers/media/platform/s5p-tv/sdo_drv.c +++ /dev/null | |||
@@ -1,497 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung Standard Definition Output (SDO) driver | ||
3 | * | ||
4 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
5 | * | ||
6 | * Tomasz Stanislawski, <t.stanislaws@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 as published | ||
10 | * by the Free Software Foundiation. either version 2 of the License, | ||
11 | * or (at your option) any later version | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #include <media/v4l2-subdev.h> | ||
27 | |||
28 | #include "regs-sdo.h" | ||
29 | |||
30 | MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>"); | ||
31 | MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)"); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | |||
34 | #define SDO_DEFAULT_STD V4L2_STD_PAL | ||
35 | |||
36 | struct sdo_format { | ||
37 | v4l2_std_id id; | ||
38 | /* all modes are 720 pixels wide */ | ||
39 | unsigned int height; | ||
40 | unsigned int cookie; | ||
41 | }; | ||
42 | |||
43 | struct sdo_device { | ||
44 | /** pointer to device parent */ | ||
45 | struct device *dev; | ||
46 | /** base address of SDO registers */ | ||
47 | void __iomem *regs; | ||
48 | /** SDO interrupt */ | ||
49 | unsigned int irq; | ||
50 | /** DAC source clock */ | ||
51 | struct clk *sclk_dac; | ||
52 | /** DAC clock */ | ||
53 | struct clk *dac; | ||
54 | /** DAC physical interface */ | ||
55 | struct clk *dacphy; | ||
56 | /** clock for control of VPLL */ | ||
57 | struct clk *fout_vpll; | ||
58 | /** vpll rate before sdo stream was on */ | ||
59 | unsigned long vpll_rate; | ||
60 | /** regulator for SDO IP power */ | ||
61 | struct regulator *vdac; | ||
62 | /** regulator for SDO plug detection */ | ||
63 | struct regulator *vdet; | ||
64 | /** subdev used as device interface */ | ||
65 | struct v4l2_subdev sd; | ||
66 | /** current format */ | ||
67 | const struct sdo_format *fmt; | ||
68 | }; | ||
69 | |||
70 | static inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd) | ||
71 | { | ||
72 | return container_of(sd, struct sdo_device, sd); | ||
73 | } | ||
74 | |||
75 | static inline | ||
76 | void sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask) | ||
77 | { | ||
78 | u32 old = readl(sdev->regs + reg_id); | ||
79 | value = (value & mask) | (old & ~mask); | ||
80 | writel(value, sdev->regs + reg_id); | ||
81 | } | ||
82 | |||
83 | static inline | ||
84 | void sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value) | ||
85 | { | ||
86 | writel(value, sdev->regs + reg_id); | ||
87 | } | ||
88 | |||
89 | static inline | ||
90 | u32 sdo_read(struct sdo_device *sdev, u32 reg_id) | ||
91 | { | ||
92 | return readl(sdev->regs + reg_id); | ||
93 | } | ||
94 | |||
95 | static irqreturn_t sdo_irq_handler(int irq, void *dev_data) | ||
96 | { | ||
97 | struct sdo_device *sdev = dev_data; | ||
98 | |||
99 | /* clear interrupt */ | ||
100 | sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND); | ||
101 | return IRQ_HANDLED; | ||
102 | } | ||
103 | |||
104 | static void sdo_reg_debug(struct sdo_device *sdev) | ||
105 | { | ||
106 | #define DBGREG(reg_id) \ | ||
107 | dev_info(sdev->dev, #reg_id " = %08x\n", \ | ||
108 | sdo_read(sdev, reg_id)) | ||
109 | |||
110 | DBGREG(SDO_CLKCON); | ||
111 | DBGREG(SDO_CONFIG); | ||
112 | DBGREG(SDO_VBI); | ||
113 | DBGREG(SDO_DAC); | ||
114 | DBGREG(SDO_IRQ); | ||
115 | DBGREG(SDO_IRQMASK); | ||
116 | DBGREG(SDO_VERSION); | ||
117 | } | ||
118 | |||
119 | static const struct sdo_format sdo_format[] = { | ||
120 | { V4L2_STD_PAL_N, .height = 576, .cookie = SDO_PAL_N }, | ||
121 | { V4L2_STD_PAL_Nc, .height = 576, .cookie = SDO_PAL_NC }, | ||
122 | { V4L2_STD_PAL_M, .height = 480, .cookie = SDO_PAL_M }, | ||
123 | { V4L2_STD_PAL_60, .height = 480, .cookie = SDO_PAL_60 }, | ||
124 | { V4L2_STD_NTSC_443, .height = 480, .cookie = SDO_NTSC_443 }, | ||
125 | { V4L2_STD_PAL, .height = 576, .cookie = SDO_PAL_BGHID }, | ||
126 | { V4L2_STD_NTSC_M, .height = 480, .cookie = SDO_NTSC_M }, | ||
127 | }; | ||
128 | |||
129 | static const struct sdo_format *sdo_find_format(v4l2_std_id id) | ||
130 | { | ||
131 | int i; | ||
132 | for (i = 0; i < ARRAY_SIZE(sdo_format); ++i) | ||
133 | if (sdo_format[i].id & id) | ||
134 | return &sdo_format[i]; | ||
135 | return NULL; | ||
136 | } | ||
137 | |||
138 | static int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std) | ||
139 | { | ||
140 | *std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL | | ||
141 | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | | ||
142 | V4L2_STD_NTSC_443 | V4L2_STD_PAL_60; | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) | ||
147 | { | ||
148 | struct sdo_device *sdev = sd_to_sdev(sd); | ||
149 | const struct sdo_format *fmt; | ||
150 | fmt = sdo_find_format(std); | ||
151 | if (fmt == NULL) | ||
152 | return -EINVAL; | ||
153 | sdev->fmt = fmt; | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std) | ||
158 | { | ||
159 | *std = sd_to_sdev(sd)->fmt->id; | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int sdo_get_fmt(struct v4l2_subdev *sd, | ||
164 | struct v4l2_subdev_pad_config *cfg, | ||
165 | struct v4l2_subdev_format *format) | ||
166 | { | ||
167 | struct v4l2_mbus_framefmt *fmt = &format->format; | ||
168 | struct sdo_device *sdev = sd_to_sdev(sd); | ||
169 | |||
170 | if (!sdev->fmt) | ||
171 | return -ENXIO; | ||
172 | if (format->pad) | ||
173 | return -EINVAL; | ||
174 | /* all modes are 720 pixels wide */ | ||
175 | fmt->width = 720; | ||
176 | fmt->height = sdev->fmt->height; | ||
177 | fmt->code = MEDIA_BUS_FMT_FIXED; | ||
178 | fmt->field = V4L2_FIELD_INTERLACED; | ||
179 | fmt->colorspace = V4L2_COLORSPACE_JPEG; | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int sdo_s_power(struct v4l2_subdev *sd, int on) | ||
184 | { | ||
185 | struct sdo_device *sdev = sd_to_sdev(sd); | ||
186 | struct device *dev = sdev->dev; | ||
187 | int ret; | ||
188 | |||
189 | dev_info(dev, "sdo_s_power(%d)\n", on); | ||
190 | |||
191 | if (on) | ||
192 | ret = pm_runtime_get_sync(dev); | ||
193 | else | ||
194 | ret = pm_runtime_put_sync(dev); | ||
195 | |||
196 | /* only values < 0 indicate errors */ | ||
197 | return ret < 0 ? ret : 0; | ||
198 | } | ||
199 | |||
200 | static int sdo_streamon(struct sdo_device *sdev) | ||
201 | { | ||
202 | int ret; | ||
203 | |||
204 | /* set proper clock for Timing Generator */ | ||
205 | sdev->vpll_rate = clk_get_rate(sdev->fout_vpll); | ||
206 | ret = clk_set_rate(sdev->fout_vpll, 54000000); | ||
207 | if (ret < 0) { | ||
208 | dev_err(sdev->dev, "Failed to set vpll rate\n"); | ||
209 | return ret; | ||
210 | } | ||
211 | dev_info(sdev->dev, "fout_vpll.rate = %lu\n", | ||
212 | clk_get_rate(sdev->fout_vpll)); | ||
213 | /* enable clock in SDO */ | ||
214 | sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON); | ||
215 | ret = clk_prepare_enable(sdev->dacphy); | ||
216 | if (ret < 0) { | ||
217 | dev_err(sdev->dev, "clk_prepare_enable(dacphy) failed\n"); | ||
218 | goto fail; | ||
219 | } | ||
220 | /* enable DAC */ | ||
221 | sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC); | ||
222 | sdo_reg_debug(sdev); | ||
223 | return 0; | ||
224 | |||
225 | fail: | ||
226 | sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON); | ||
227 | clk_set_rate(sdev->fout_vpll, sdev->vpll_rate); | ||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | static int sdo_streamoff(struct sdo_device *sdev) | ||
232 | { | ||
233 | int tries; | ||
234 | |||
235 | sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC); | ||
236 | clk_disable_unprepare(sdev->dacphy); | ||
237 | sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON); | ||
238 | for (tries = 100; tries; --tries) { | ||
239 | if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY) | ||
240 | break; | ||
241 | mdelay(1); | ||
242 | } | ||
243 | if (tries == 0) | ||
244 | dev_err(sdev->dev, "failed to stop streaming\n"); | ||
245 | clk_set_rate(sdev->fout_vpll, sdev->vpll_rate); | ||
246 | return tries ? 0 : -EIO; | ||
247 | } | ||
248 | |||
249 | static int sdo_s_stream(struct v4l2_subdev *sd, int on) | ||
250 | { | ||
251 | struct sdo_device *sdev = sd_to_sdev(sd); | ||
252 | return on ? sdo_streamon(sdev) : sdo_streamoff(sdev); | ||
253 | } | ||
254 | |||
255 | static const struct v4l2_subdev_core_ops sdo_sd_core_ops = { | ||
256 | .s_power = sdo_s_power, | ||
257 | }; | ||
258 | |||
259 | static const struct v4l2_subdev_video_ops sdo_sd_video_ops = { | ||
260 | .s_std_output = sdo_s_std_output, | ||
261 | .g_std_output = sdo_g_std_output, | ||
262 | .g_tvnorms_output = sdo_g_tvnorms_output, | ||
263 | .s_stream = sdo_s_stream, | ||
264 | }; | ||
265 | |||
266 | static const struct v4l2_subdev_pad_ops sdo_sd_pad_ops = { | ||
267 | .get_fmt = sdo_get_fmt, | ||
268 | }; | ||
269 | |||
270 | static const struct v4l2_subdev_ops sdo_sd_ops = { | ||
271 | .core = &sdo_sd_core_ops, | ||
272 | .video = &sdo_sd_video_ops, | ||
273 | .pad = &sdo_sd_pad_ops, | ||
274 | }; | ||
275 | |||
276 | static int sdo_runtime_suspend(struct device *dev) | ||
277 | { | ||
278 | struct v4l2_subdev *sd = dev_get_drvdata(dev); | ||
279 | struct sdo_device *sdev = sd_to_sdev(sd); | ||
280 | |||
281 | dev_info(dev, "suspend\n"); | ||
282 | regulator_disable(sdev->vdet); | ||
283 | regulator_disable(sdev->vdac); | ||
284 | clk_disable_unprepare(sdev->sclk_dac); | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int sdo_runtime_resume(struct device *dev) | ||
289 | { | ||
290 | struct v4l2_subdev *sd = dev_get_drvdata(dev); | ||
291 | struct sdo_device *sdev = sd_to_sdev(sd); | ||
292 | int ret; | ||
293 | |||
294 | dev_info(dev, "resume\n"); | ||
295 | |||
296 | ret = clk_prepare_enable(sdev->sclk_dac); | ||
297 | if (ret < 0) | ||
298 | return ret; | ||
299 | |||
300 | ret = regulator_enable(sdev->vdac); | ||
301 | if (ret < 0) | ||
302 | goto dac_clk_dis; | ||
303 | |||
304 | ret = regulator_enable(sdev->vdet); | ||
305 | if (ret < 0) | ||
306 | goto vdac_r_dis; | ||
307 | |||
308 | /* software reset */ | ||
309 | sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET); | ||
310 | mdelay(10); | ||
311 | sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET); | ||
312 | |||
313 | /* setting TV mode */ | ||
314 | sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK); | ||
315 | /* XXX: forcing interlaced mode using undocumented bit */ | ||
316 | sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE); | ||
317 | /* turn all VBI off */ | ||
318 | sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS | | ||
319 | SDO_CVBS_CLOSED_CAPTION_MASK); | ||
320 | /* turn all post processing off */ | ||
321 | sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF | | ||
322 | SDO_COMPENSATION_CVBS_COMP_OFF); | ||
323 | sdo_reg_debug(sdev); | ||
324 | return 0; | ||
325 | |||
326 | vdac_r_dis: | ||
327 | regulator_disable(sdev->vdac); | ||
328 | dac_clk_dis: | ||
329 | clk_disable_unprepare(sdev->sclk_dac); | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | static const struct dev_pm_ops sdo_pm_ops = { | ||
334 | .runtime_suspend = sdo_runtime_suspend, | ||
335 | .runtime_resume = sdo_runtime_resume, | ||
336 | }; | ||
337 | |||
338 | static int sdo_probe(struct platform_device *pdev) | ||
339 | { | ||
340 | struct device *dev = &pdev->dev; | ||
341 | struct sdo_device *sdev; | ||
342 | struct resource *res; | ||
343 | int ret = 0; | ||
344 | struct clk *sclk_vpll; | ||
345 | |||
346 | dev_info(dev, "probe start\n"); | ||
347 | sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL); | ||
348 | if (!sdev) { | ||
349 | dev_err(dev, "not enough memory.\n"); | ||
350 | ret = -ENOMEM; | ||
351 | goto fail; | ||
352 | } | ||
353 | sdev->dev = dev; | ||
354 | |||
355 | /* mapping registers */ | ||
356 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
357 | if (res == NULL) { | ||
358 | dev_err(dev, "get memory resource failed.\n"); | ||
359 | ret = -ENXIO; | ||
360 | goto fail; | ||
361 | } | ||
362 | |||
363 | sdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); | ||
364 | if (sdev->regs == NULL) { | ||
365 | dev_err(dev, "register mapping failed.\n"); | ||
366 | ret = -ENXIO; | ||
367 | goto fail; | ||
368 | } | ||
369 | |||
370 | /* acquiring interrupt */ | ||
371 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
372 | if (res == NULL) { | ||
373 | dev_err(dev, "get interrupt resource failed.\n"); | ||
374 | ret = -ENXIO; | ||
375 | goto fail; | ||
376 | } | ||
377 | ret = devm_request_irq(&pdev->dev, res->start, sdo_irq_handler, 0, | ||
378 | "s5p-sdo", sdev); | ||
379 | if (ret) { | ||
380 | dev_err(dev, "request interrupt failed.\n"); | ||
381 | goto fail; | ||
382 | } | ||
383 | sdev->irq = res->start; | ||
384 | |||
385 | /* acquire clocks */ | ||
386 | sdev->sclk_dac = clk_get(dev, "sclk_dac"); | ||
387 | if (IS_ERR(sdev->sclk_dac)) { | ||
388 | dev_err(dev, "failed to get clock 'sclk_dac'\n"); | ||
389 | ret = PTR_ERR(sdev->sclk_dac); | ||
390 | goto fail; | ||
391 | } | ||
392 | sdev->dac = clk_get(dev, "dac"); | ||
393 | if (IS_ERR(sdev->dac)) { | ||
394 | dev_err(dev, "failed to get clock 'dac'\n"); | ||
395 | ret = PTR_ERR(sdev->dac); | ||
396 | goto fail_sclk_dac; | ||
397 | } | ||
398 | sdev->dacphy = clk_get(dev, "dacphy"); | ||
399 | if (IS_ERR(sdev->dacphy)) { | ||
400 | dev_err(dev, "failed to get clock 'dacphy'\n"); | ||
401 | ret = PTR_ERR(sdev->dacphy); | ||
402 | goto fail_dac; | ||
403 | } | ||
404 | sclk_vpll = clk_get(dev, "sclk_vpll"); | ||
405 | if (IS_ERR(sclk_vpll)) { | ||
406 | dev_err(dev, "failed to get clock 'sclk_vpll'\n"); | ||
407 | ret = PTR_ERR(sclk_vpll); | ||
408 | goto fail_dacphy; | ||
409 | } | ||
410 | clk_set_parent(sdev->sclk_dac, sclk_vpll); | ||
411 | clk_put(sclk_vpll); | ||
412 | sdev->fout_vpll = clk_get(dev, "fout_vpll"); | ||
413 | if (IS_ERR(sdev->fout_vpll)) { | ||
414 | dev_err(dev, "failed to get clock 'fout_vpll'\n"); | ||
415 | ret = PTR_ERR(sdev->fout_vpll); | ||
416 | goto fail_dacphy; | ||
417 | } | ||
418 | dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll)); | ||
419 | |||
420 | /* acquire regulator */ | ||
421 | sdev->vdac = devm_regulator_get(dev, "vdd33a_dac"); | ||
422 | if (IS_ERR(sdev->vdac)) { | ||
423 | dev_err(dev, "failed to get regulator 'vdac'\n"); | ||
424 | ret = PTR_ERR(sdev->vdac); | ||
425 | goto fail_fout_vpll; | ||
426 | } | ||
427 | sdev->vdet = devm_regulator_get(dev, "vdet"); | ||
428 | if (IS_ERR(sdev->vdet)) { | ||
429 | dev_err(dev, "failed to get regulator 'vdet'\n"); | ||
430 | ret = PTR_ERR(sdev->vdet); | ||
431 | goto fail_fout_vpll; | ||
432 | } | ||
433 | |||
434 | /* enable gate for dac clock, because mixer uses it */ | ||
435 | ret = clk_prepare_enable(sdev->dac); | ||
436 | if (ret < 0) { | ||
437 | dev_err(dev, "clk_prepare_enable(dac) failed\n"); | ||
438 | goto fail_fout_vpll; | ||
439 | } | ||
440 | |||
441 | /* configure power management */ | ||
442 | pm_runtime_enable(dev); | ||
443 | |||
444 | /* configuration of interface subdevice */ | ||
445 | v4l2_subdev_init(&sdev->sd, &sdo_sd_ops); | ||
446 | sdev->sd.owner = THIS_MODULE; | ||
447 | strlcpy(sdev->sd.name, "s5p-sdo", sizeof(sdev->sd.name)); | ||
448 | |||
449 | /* set default format */ | ||
450 | sdev->fmt = sdo_find_format(SDO_DEFAULT_STD); | ||
451 | BUG_ON(sdev->fmt == NULL); | ||
452 | |||
453 | /* keeping subdev in device's private for use by other drivers */ | ||
454 | dev_set_drvdata(dev, &sdev->sd); | ||
455 | |||
456 | dev_info(dev, "probe succeeded\n"); | ||
457 | return 0; | ||
458 | |||
459 | fail_fout_vpll: | ||
460 | clk_put(sdev->fout_vpll); | ||
461 | fail_dacphy: | ||
462 | clk_put(sdev->dacphy); | ||
463 | fail_dac: | ||
464 | clk_put(sdev->dac); | ||
465 | fail_sclk_dac: | ||
466 | clk_put(sdev->sclk_dac); | ||
467 | fail: | ||
468 | dev_info(dev, "probe failed\n"); | ||
469 | return ret; | ||
470 | } | ||
471 | |||
472 | static int sdo_remove(struct platform_device *pdev) | ||
473 | { | ||
474 | struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev); | ||
475 | struct sdo_device *sdev = sd_to_sdev(sd); | ||
476 | |||
477 | pm_runtime_disable(&pdev->dev); | ||
478 | clk_disable_unprepare(sdev->dac); | ||
479 | clk_put(sdev->fout_vpll); | ||
480 | clk_put(sdev->dacphy); | ||
481 | clk_put(sdev->dac); | ||
482 | clk_put(sdev->sclk_dac); | ||
483 | |||
484 | dev_info(&pdev->dev, "remove successful\n"); | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static struct platform_driver sdo_driver __refdata = { | ||
489 | .probe = sdo_probe, | ||
490 | .remove = sdo_remove, | ||
491 | .driver = { | ||
492 | .name = "s5p-sdo", | ||
493 | .pm = &sdo_pm_ops, | ||
494 | } | ||
495 | }; | ||
496 | |||
497 | module_platform_driver(sdo_driver); | ||
diff --git a/drivers/media/platform/s5p-tv/sii9234_drv.c b/drivers/media/platform/s5p-tv/sii9234_drv.c deleted file mode 100644 index 0a97f9ab4f76..000000000000 --- a/drivers/media/platform/s5p-tv/sii9234_drv.c +++ /dev/null | |||
@@ -1,407 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung MHL interface driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co.Ltd | ||
5 | * Author: Tomasz Stanislawski <t.stanislaws@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/delay.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/freezer.h> | ||
16 | #include <linux/gpio.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/kthread.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | #include <linux/regulator/machine.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #include <linux/platform_data/media/sii9234.h> | ||
27 | #include <media/v4l2-subdev.h> | ||
28 | |||
29 | MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>"); | ||
30 | MODULE_DESCRIPTION("Samsung MHL interface driver"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | struct sii9234_context { | ||
34 | struct i2c_client *client; | ||
35 | struct regulator *power; | ||
36 | int gpio_n_reset; | ||
37 | struct v4l2_subdev sd; | ||
38 | }; | ||
39 | |||
40 | static inline struct sii9234_context *sd_to_context(struct v4l2_subdev *sd) | ||
41 | { | ||
42 | return container_of(sd, struct sii9234_context, sd); | ||
43 | } | ||
44 | |||
45 | static inline int sii9234_readb(struct i2c_client *client, int addr) | ||
46 | { | ||
47 | return i2c_smbus_read_byte_data(client, addr); | ||
48 | } | ||
49 | |||
50 | static inline int sii9234_writeb(struct i2c_client *client, int addr, int value) | ||
51 | { | ||
52 | return i2c_smbus_write_byte_data(client, addr, value); | ||
53 | } | ||
54 | |||
55 | static inline int sii9234_writeb_mask(struct i2c_client *client, int addr, | ||
56 | int value, int mask) | ||
57 | { | ||
58 | int ret; | ||
59 | |||
60 | ret = i2c_smbus_read_byte_data(client, addr); | ||
61 | if (ret < 0) | ||
62 | return ret; | ||
63 | ret = (ret & ~mask) | (value & mask); | ||
64 | return i2c_smbus_write_byte_data(client, addr, ret); | ||
65 | } | ||
66 | |||
67 | static inline int sii9234_readb_idx(struct i2c_client *client, int addr) | ||
68 | { | ||
69 | int ret; | ||
70 | ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8); | ||
71 | if (ret < 0) | ||
72 | return ret; | ||
73 | ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff); | ||
74 | if (ret < 0) | ||
75 | return ret; | ||
76 | return i2c_smbus_read_byte_data(client, 0xbe); | ||
77 | } | ||
78 | |||
79 | static inline int sii9234_writeb_idx(struct i2c_client *client, int addr, | ||
80 | int value) | ||
81 | { | ||
82 | int ret; | ||
83 | ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8); | ||
84 | if (ret < 0) | ||
85 | return ret; | ||
86 | ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff); | ||
87 | if (ret < 0) | ||
88 | return ret; | ||
89 | ret = i2c_smbus_write_byte_data(client, 0xbe, value); | ||
90 | return ret; | ||
91 | } | ||
92 | |||
93 | static inline int sii9234_writeb_idx_mask(struct i2c_client *client, int addr, | ||
94 | int value, int mask) | ||
95 | { | ||
96 | int ret; | ||
97 | |||
98 | ret = sii9234_readb_idx(client, addr); | ||
99 | if (ret < 0) | ||
100 | return ret; | ||
101 | ret = (ret & ~mask) | (value & mask); | ||
102 | return sii9234_writeb_idx(client, addr, ret); | ||
103 | } | ||
104 | |||
105 | static int sii9234_reset(struct sii9234_context *ctx) | ||
106 | { | ||
107 | struct i2c_client *client = ctx->client; | ||
108 | struct device *dev = &client->dev; | ||
109 | int ret, tries; | ||
110 | |||
111 | gpio_direction_output(ctx->gpio_n_reset, 1); | ||
112 | mdelay(1); | ||
113 | gpio_direction_output(ctx->gpio_n_reset, 0); | ||
114 | mdelay(1); | ||
115 | gpio_direction_output(ctx->gpio_n_reset, 1); | ||
116 | mdelay(1); | ||
117 | |||
118 | /* going to TTPI mode */ | ||
119 | ret = sii9234_writeb(client, 0xc7, 0); | ||
120 | if (ret < 0) { | ||
121 | dev_err(dev, "failed to set TTPI mode\n"); | ||
122 | return ret; | ||
123 | } | ||
124 | for (tries = 0; tries < 100 ; ++tries) { | ||
125 | ret = sii9234_readb(client, 0x1b); | ||
126 | if (ret > 0) | ||
127 | break; | ||
128 | if (ret < 0) { | ||
129 | dev_err(dev, "failed to reset device\n"); | ||
130 | return -EIO; | ||
131 | } | ||
132 | mdelay(1); | ||
133 | } | ||
134 | if (tries == 100) { | ||
135 | dev_err(dev, "maximal number of tries reached\n"); | ||
136 | return -EIO; | ||
137 | } | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int sii9234_verify_version(struct i2c_client *client) | ||
143 | { | ||
144 | struct device *dev = &client->dev; | ||
145 | int family, rev, tpi_rev, dev_id, sub_id, hdcp, id; | ||
146 | |||
147 | family = sii9234_readb(client, 0x1b); | ||
148 | rev = sii9234_readb(client, 0x1c) & 0x0f; | ||
149 | tpi_rev = sii9234_readb(client, 0x1d) & 0x7f; | ||
150 | dev_id = sii9234_readb_idx(client, 0x0103); | ||
151 | sub_id = sii9234_readb_idx(client, 0x0102); | ||
152 | hdcp = sii9234_readb(client, 0x30); | ||
153 | |||
154 | if (family < 0 || rev < 0 || tpi_rev < 0 || dev_id < 0 || | ||
155 | sub_id < 0 || hdcp < 0) { | ||
156 | dev_err(dev, "failed to read chip's version\n"); | ||
157 | return -EIO; | ||
158 | } | ||
159 | |||
160 | id = (dev_id << 8) | sub_id; | ||
161 | |||
162 | dev_info(dev, "chip: SiL%02x family: %02x, rev: %02x\n", | ||
163 | id, family, rev); | ||
164 | dev_info(dev, "tpi_rev:%02x, hdcp: %02x\n", tpi_rev, hdcp); | ||
165 | if (id != 0x9234) { | ||
166 | dev_err(dev, "not supported chip\n"); | ||
167 | return -ENODEV; | ||
168 | } | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static u8 data[][3] = { | ||
174 | /* setup from driver created by doonsoo45.kim */ | ||
175 | { 0x01, 0x05, 0x04 }, /* Enable Auto soft reset on SCDT = 0 */ | ||
176 | { 0x01, 0x08, 0x35 }, /* Power Up TMDS Tx Core */ | ||
177 | { 0x01, 0x0d, 0x1c }, /* HDMI Transcode mode enable */ | ||
178 | { 0x01, 0x2b, 0x01 }, /* Enable HDCP Compliance workaround */ | ||
179 | { 0x01, 0x79, 0x40 }, /* daniel test...MHL_INT */ | ||
180 | { 0x01, 0x80, 0x34 }, /* Enable Rx PLL Clock Value */ | ||
181 | { 0x01, 0x90, 0x27 }, /* Enable CBUS discovery */ | ||
182 | { 0x01, 0x91, 0xe5 }, /* Skip RGND detection */ | ||
183 | { 0x01, 0x92, 0x46 }, /* Force MHD mode */ | ||
184 | { 0x01, 0x93, 0xdc }, /* Disable CBUS pull-up during RGND measurement */ | ||
185 | { 0x01, 0x94, 0x66 }, /* 1.8V CBUS VTH & GND threshold */ | ||
186 | { 0x01, 0x95, 0x31 }, /* RGND block & single discovery attempt */ | ||
187 | { 0x01, 0x96, 0x22 }, /* use 1K and 2K setting */ | ||
188 | { 0x01, 0xa0, 0x10 }, /* SIMG: Term mode */ | ||
189 | { 0x01, 0xa1, 0xfc }, /* Disable internal Mobile HD driver */ | ||
190 | { 0x01, 0xa3, 0xfa }, /* SIMG: Output Swing default EB, 3x Clk Mult */ | ||
191 | { 0x01, 0xa5, 0x80 }, /* SIMG: RGND Hysterisis, 3x mode for Beast */ | ||
192 | { 0x01, 0xa6, 0x0c }, /* SIMG: Swing Offset */ | ||
193 | { 0x02, 0x3d, 0x3f }, /* Power up CVCC 1.2V core */ | ||
194 | { 0x03, 0x00, 0x00 }, /* SIMG: correcting HW default */ | ||
195 | { 0x03, 0x11, 0x01 }, /* Enable TxPLL Clock */ | ||
196 | { 0x03, 0x12, 0x15 }, /* Enable Tx Clock Path & Equalizer */ | ||
197 | { 0x03, 0x13, 0x60 }, /* SIMG: Set termination value */ | ||
198 | { 0x03, 0x14, 0xf0 }, /* SIMG: Change CKDT level */ | ||
199 | { 0x03, 0x17, 0x07 }, /* SIMG: PLL Calrefsel */ | ||
200 | { 0x03, 0x1a, 0x20 }, /* VCO Cal */ | ||
201 | { 0x03, 0x22, 0xe0 }, /* SIMG: Auto EQ */ | ||
202 | { 0x03, 0x23, 0xc0 }, /* SIMG: Auto EQ */ | ||
203 | { 0x03, 0x24, 0xa0 }, /* SIMG: Auto EQ */ | ||
204 | { 0x03, 0x25, 0x80 }, /* SIMG: Auto EQ */ | ||
205 | { 0x03, 0x26, 0x60 }, /* SIMG: Auto EQ */ | ||
206 | { 0x03, 0x27, 0x40 }, /* SIMG: Auto EQ */ | ||
207 | { 0x03, 0x28, 0x20 }, /* SIMG: Auto EQ */ | ||
208 | { 0x03, 0x29, 0x00 }, /* SIMG: Auto EQ */ | ||
209 | { 0x03, 0x31, 0x0b }, /* SIMG: Rx PLL BW value from I2C BW ~ 4MHz */ | ||
210 | { 0x03, 0x45, 0x06 }, /* SIMG: DPLL Mode */ | ||
211 | { 0x03, 0x4b, 0x06 }, /* SIMG: Correcting HW default */ | ||
212 | { 0x03, 0x4c, 0xa0 }, /* Manual zone control */ | ||
213 | { 0x03, 0x4d, 0x02 }, /* SIMG: PLL Mode Value (order is important) */ | ||
214 | }; | ||
215 | |||
216 | static int sii9234_set_internal(struct sii9234_context *ctx) | ||
217 | { | ||
218 | struct i2c_client *client = ctx->client; | ||
219 | int i, ret; | ||
220 | |||
221 | for (i = 0; i < ARRAY_SIZE(data); ++i) { | ||
222 | int addr = (data[i][0] << 8) | data[i][1]; | ||
223 | ret = sii9234_writeb_idx(client, addr, data[i][2]); | ||
224 | if (ret < 0) | ||
225 | return ret; | ||
226 | } | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int sii9234_runtime_suspend(struct device *dev) | ||
231 | { | ||
232 | struct v4l2_subdev *sd = dev_get_drvdata(dev); | ||
233 | struct sii9234_context *ctx = sd_to_context(sd); | ||
234 | struct i2c_client *client = ctx->client; | ||
235 | |||
236 | dev_info(dev, "suspend start\n"); | ||
237 | |||
238 | sii9234_writeb_mask(client, 0x1e, 3, 3); | ||
239 | regulator_disable(ctx->power); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int sii9234_runtime_resume(struct device *dev) | ||
245 | { | ||
246 | struct v4l2_subdev *sd = dev_get_drvdata(dev); | ||
247 | struct sii9234_context *ctx = sd_to_context(sd); | ||
248 | struct i2c_client *client = ctx->client; | ||
249 | int ret; | ||
250 | |||
251 | dev_info(dev, "resume start\n"); | ||
252 | ret = regulator_enable(ctx->power); | ||
253 | if (ret < 0) | ||
254 | return ret; | ||
255 | |||
256 | ret = sii9234_reset(ctx); | ||
257 | if (ret) | ||
258 | goto fail; | ||
259 | |||
260 | /* enable tpi */ | ||
261 | ret = sii9234_writeb_mask(client, 0x1e, 1, 0); | ||
262 | if (ret < 0) | ||
263 | goto fail; | ||
264 | ret = sii9234_set_internal(ctx); | ||
265 | if (ret < 0) | ||
266 | goto fail; | ||
267 | |||
268 | return 0; | ||
269 | |||
270 | fail: | ||
271 | dev_err(dev, "failed to resume\n"); | ||
272 | regulator_disable(ctx->power); | ||
273 | |||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | static const struct dev_pm_ops sii9234_pm_ops = { | ||
278 | .runtime_suspend = sii9234_runtime_suspend, | ||
279 | .runtime_resume = sii9234_runtime_resume, | ||
280 | }; | ||
281 | |||
282 | static int sii9234_s_power(struct v4l2_subdev *sd, int on) | ||
283 | { | ||
284 | struct sii9234_context *ctx = sd_to_context(sd); | ||
285 | int ret; | ||
286 | |||
287 | if (on) | ||
288 | ret = pm_runtime_get_sync(&ctx->client->dev); | ||
289 | else | ||
290 | ret = pm_runtime_put(&ctx->client->dev); | ||
291 | /* only values < 0 indicate errors */ | ||
292 | return ret < 0 ? ret : 0; | ||
293 | } | ||
294 | |||
295 | static int sii9234_s_stream(struct v4l2_subdev *sd, int enable) | ||
296 | { | ||
297 | struct sii9234_context *ctx = sd_to_context(sd); | ||
298 | |||
299 | /* (dis/en)able TDMS output */ | ||
300 | sii9234_writeb_mask(ctx->client, 0x1a, enable ? 0 : ~0 , 1 << 4); | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static const struct v4l2_subdev_core_ops sii9234_core_ops = { | ||
305 | .s_power = sii9234_s_power, | ||
306 | }; | ||
307 | |||
308 | static const struct v4l2_subdev_video_ops sii9234_video_ops = { | ||
309 | .s_stream = sii9234_s_stream, | ||
310 | }; | ||
311 | |||
312 | static const struct v4l2_subdev_ops sii9234_ops = { | ||
313 | .core = &sii9234_core_ops, | ||
314 | .video = &sii9234_video_ops, | ||
315 | }; | ||
316 | |||
317 | static int sii9234_probe(struct i2c_client *client, | ||
318 | const struct i2c_device_id *id) | ||
319 | { | ||
320 | struct device *dev = &client->dev; | ||
321 | struct sii9234_platform_data *pdata = dev->platform_data; | ||
322 | struct sii9234_context *ctx; | ||
323 | int ret; | ||
324 | |||
325 | ctx = devm_kzalloc(&client->dev, sizeof(*ctx), GFP_KERNEL); | ||
326 | if (!ctx) { | ||
327 | dev_err(dev, "out of memory\n"); | ||
328 | ret = -ENOMEM; | ||
329 | goto fail; | ||
330 | } | ||
331 | ctx->client = client; | ||
332 | |||
333 | ctx->power = devm_regulator_get(dev, "hdmi-en"); | ||
334 | if (IS_ERR(ctx->power)) { | ||
335 | dev_err(dev, "failed to acquire regulator hdmi-en\n"); | ||
336 | return PTR_ERR(ctx->power); | ||
337 | } | ||
338 | |||
339 | ctx->gpio_n_reset = pdata->gpio_n_reset; | ||
340 | ret = devm_gpio_request(dev, ctx->gpio_n_reset, "MHL_RST"); | ||
341 | if (ret) { | ||
342 | dev_err(dev, "failed to acquire MHL_RST gpio\n"); | ||
343 | return ret; | ||
344 | } | ||
345 | |||
346 | v4l2_i2c_subdev_init(&ctx->sd, client, &sii9234_ops); | ||
347 | |||
348 | pm_runtime_enable(dev); | ||
349 | |||
350 | /* enable device */ | ||
351 | ret = pm_runtime_get_sync(dev); | ||
352 | if (ret) | ||
353 | goto fail_pm; | ||
354 | |||
355 | /* verify chip version */ | ||
356 | ret = sii9234_verify_version(client); | ||
357 | if (ret) | ||
358 | goto fail_pm_get; | ||
359 | |||
360 | /* stop processing */ | ||
361 | pm_runtime_put(dev); | ||
362 | |||
363 | dev_info(dev, "probe successful\n"); | ||
364 | |||
365 | return 0; | ||
366 | |||
367 | fail_pm_get: | ||
368 | pm_runtime_put_sync(dev); | ||
369 | |||
370 | fail_pm: | ||
371 | pm_runtime_disable(dev); | ||
372 | |||
373 | fail: | ||
374 | dev_err(dev, "probe failed\n"); | ||
375 | |||
376 | return ret; | ||
377 | } | ||
378 | |||
379 | static int sii9234_remove(struct i2c_client *client) | ||
380 | { | ||
381 | struct device *dev = &client->dev; | ||
382 | |||
383 | pm_runtime_disable(dev); | ||
384 | |||
385 | dev_info(dev, "remove successful\n"); | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | |||
391 | static const struct i2c_device_id sii9234_id[] = { | ||
392 | { "SII9234", 0 }, | ||
393 | { }, | ||
394 | }; | ||
395 | |||
396 | MODULE_DEVICE_TABLE(i2c, sii9234_id); | ||
397 | static struct i2c_driver sii9234_driver = { | ||
398 | .driver = { | ||
399 | .name = "sii9234", | ||
400 | .pm = &sii9234_pm_ops, | ||
401 | }, | ||
402 | .probe = sii9234_probe, | ||
403 | .remove = sii9234_remove, | ||
404 | .id_table = sii9234_id, | ||
405 | }; | ||
406 | |||
407 | module_i2c_driver(sii9234_driver); | ||
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index e1f39b4cf1cd..ef2a519bcd4c 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c | |||
@@ -362,7 +362,7 @@ static void sh_vou_stop_streaming(struct vb2_queue *vq) | |||
362 | spin_unlock_irqrestore(&vou_dev->lock, flags); | 362 | spin_unlock_irqrestore(&vou_dev->lock, flags); |
363 | } | 363 | } |
364 | 364 | ||
365 | static struct vb2_ops sh_vou_qops = { | 365 | static const struct vb2_ops sh_vou_qops = { |
366 | .queue_setup = sh_vou_queue_setup, | 366 | .queue_setup = sh_vou_queue_setup, |
367 | .buf_prepare = sh_vou_buf_prepare, | 367 | .buf_prepare = sh_vou_buf_prepare, |
368 | .buf_queue = sh_vou_buf_queue, | 368 | .buf_queue = sh_vou_buf_queue, |
@@ -937,7 +937,10 @@ static int sh_vou_s_selection(struct file *file, void *fh, | |||
937 | { | 937 | { |
938 | struct v4l2_rect *rect = &sel->r; | 938 | struct v4l2_rect *rect = &sel->r; |
939 | struct sh_vou_device *vou_dev = video_drvdata(file); | 939 | struct sh_vou_device *vou_dev = video_drvdata(file); |
940 | struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT}; | 940 | struct v4l2_subdev_selection sd_sel = { |
941 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
942 | .target = V4L2_SEL_TGT_COMPOSE, | ||
943 | }; | ||
941 | struct v4l2_pix_format *pix = &vou_dev->pix; | 944 | struct v4l2_pix_format *pix = &vou_dev->pix; |
942 | struct sh_vou_geometry geo; | 945 | struct sh_vou_geometry geo; |
943 | struct v4l2_subdev_format format = { | 946 | struct v4l2_subdev_format format = { |
@@ -978,14 +981,14 @@ static int sh_vou_s_selection(struct file *file, void *fh, | |||
978 | geo.in_height = pix->height; | 981 | geo.in_height = pix->height; |
979 | 982 | ||
980 | /* Configure the encoder one-to-one, position at 0, ignore errors */ | 983 | /* Configure the encoder one-to-one, position at 0, ignore errors */ |
981 | sd_crop.c.width = geo.output.width; | 984 | sd_sel.r.width = geo.output.width; |
982 | sd_crop.c.height = geo.output.height; | 985 | sd_sel.r.height = geo.output.height; |
983 | /* | 986 | /* |
984 | * We first issue a S_CROP, so that the subsequent S_FMT delivers the | 987 | * We first issue a S_SELECTION, so that the subsequent S_FMT delivers the |
985 | * final encoder configuration. | 988 | * final encoder configuration. |
986 | */ | 989 | */ |
987 | v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, | 990 | v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad, |
988 | s_crop, &sd_crop); | 991 | set_selection, NULL, &sd_sel); |
989 | format.format.width = geo.output.width; | 992 | format.format.width = geo.output.width; |
990 | format.format.height = geo.output.height; | 993 | format.format.height = geo.output.height; |
991 | ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad, | 994 | ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad, |
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig index 39f66414f621..86d74788544f 100644 --- a/drivers/media/platform/soc_camera/Kconfig +++ b/drivers/media/platform/soc_camera/Kconfig | |||
@@ -17,31 +17,6 @@ config SOC_CAMERA_PLATFORM | |||
17 | help | 17 | help |
18 | This is a generic SoC camera platform driver, useful for testing | 18 | This is a generic SoC camera platform driver, useful for testing |
19 | 19 | ||
20 | config VIDEO_PXA27x | ||
21 | tristate "PXA27x Quick Capture Interface driver" | ||
22 | depends on VIDEO_DEV && PXA27x && SOC_CAMERA | ||
23 | select VIDEOBUF_DMA_SG | ||
24 | select SG_SPLIT | ||
25 | ---help--- | ||
26 | This is a v4l2 driver for the PXA27x Quick Capture Interface | ||
27 | |||
28 | config VIDEO_RCAR_VIN_OLD | ||
29 | tristate "R-Car Video Input (VIN) support (DEPRECATED)" | ||
30 | depends on VIDEO_DEV && SOC_CAMERA | ||
31 | depends on ARCH_RENESAS || COMPILE_TEST | ||
32 | depends on HAS_DMA | ||
33 | select VIDEOBUF2_DMA_CONTIG | ||
34 | select SOC_CAMERA_SCALE_CROP | ||
35 | ---help--- | ||
36 | This is a v4l2 driver for the R-Car VIN Interface | ||
37 | |||
38 | config VIDEO_SH_MOBILE_CSI2 | ||
39 | tristate "SuperH Mobile MIPI CSI-2 Interface driver" | ||
40 | depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK | ||
41 | depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST | ||
42 | ---help--- | ||
43 | This is a v4l2 driver for the SuperH MIPI CSI-2 Interface | ||
44 | |||
45 | config VIDEO_SH_MOBILE_CEU | 20 | config VIDEO_SH_MOBILE_CEU |
46 | tristate "SuperH Mobile CEU Interface driver" | 21 | tristate "SuperH Mobile CEU Interface driver" |
47 | depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK | 22 | depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK |
diff --git a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile index 7703cb7ce456..7633a0f2f66f 100644 --- a/drivers/media/platform/soc_camera/Makefile +++ b/drivers/media/platform/soc_camera/Makefile | |||
@@ -7,7 +7,4 @@ obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o | |||
7 | 7 | ||
8 | # soc-camera host drivers have to be linked after camera drivers | 8 | # soc-camera host drivers have to be linked after camera drivers |
9 | obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o | 9 | obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o |
10 | obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o | ||
11 | obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o | 10 | obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o |
12 | obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o | ||
13 | obj-$(CONFIG_VIDEO_RCAR_VIN_OLD) += rcar_vin.o | ||
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 30211f6b4483..46de657c3e6d 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c | |||
@@ -536,7 +536,7 @@ static void stop_streaming(struct vb2_queue *vq) | |||
536 | pm_runtime_put(ici->v4l2_dev.dev); | 536 | pm_runtime_put(ici->v4l2_dev.dev); |
537 | } | 537 | } |
538 | 538 | ||
539 | static struct vb2_ops isi_video_qops = { | 539 | static const struct vb2_ops isi_video_qops = { |
540 | .queue_setup = queue_setup, | 540 | .queue_setup = queue_setup, |
541 | .buf_init = buffer_init, | 541 | .buf_init = buffer_init, |
542 | .buf_prepare = buffer_prepare, | 542 | .buf_prepare = buffer_prepare, |
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c deleted file mode 100644 index 9c137522c660..000000000000 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ /dev/null | |||
@@ -1,1970 +0,0 @@ | |||
1 | /* | ||
2 | * SoC-camera host driver for Renesas R-Car VIN unit | ||
3 | * | ||
4 | * Copyright (C) 2011-2013 Renesas Solutions Corp. | ||
5 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> | ||
6 | * | ||
7 | * Based on V4L2 Driver for SuperH Mobile CEU interface "sh_mobile_ceu_camera.c" | ||
8 | * | ||
9 | * Copyright (C) 2008 Magnus Damm | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/delay.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/of_device.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/pm_runtime.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/videodev2.h> | ||
28 | |||
29 | #include <media/soc_camera.h> | ||
30 | #include <media/drv-intf/soc_mediabus.h> | ||
31 | #include <media/v4l2-common.h> | ||
32 | #include <media/v4l2-dev.h> | ||
33 | #include <media/v4l2-device.h> | ||
34 | #include <media/v4l2-mediabus.h> | ||
35 | #include <media/v4l2-of.h> | ||
36 | #include <media/v4l2-subdev.h> | ||
37 | #include <media/videobuf2-dma-contig.h> | ||
38 | |||
39 | #include "soc_scale_crop.h" | ||
40 | |||
41 | #define DRV_NAME "rcar_vin" | ||
42 | |||
43 | /* Register offsets for R-Car VIN */ | ||
44 | #define VNMC_REG 0x00 /* Video n Main Control Register */ | ||
45 | #define VNMS_REG 0x04 /* Video n Module Status Register */ | ||
46 | #define VNFC_REG 0x08 /* Video n Frame Capture Register */ | ||
47 | #define VNSLPRC_REG 0x0C /* Video n Start Line Pre-Clip Register */ | ||
48 | #define VNELPRC_REG 0x10 /* Video n End Line Pre-Clip Register */ | ||
49 | #define VNSPPRC_REG 0x14 /* Video n Start Pixel Pre-Clip Register */ | ||
50 | #define VNEPPRC_REG 0x18 /* Video n End Pixel Pre-Clip Register */ | ||
51 | #define VNSLPOC_REG 0x1C /* Video n Start Line Post-Clip Register */ | ||
52 | #define VNELPOC_REG 0x20 /* Video n End Line Post-Clip Register */ | ||
53 | #define VNSPPOC_REG 0x24 /* Video n Start Pixel Post-Clip Register */ | ||
54 | #define VNEPPOC_REG 0x28 /* Video n End Pixel Post-Clip Register */ | ||
55 | #define VNIS_REG 0x2C /* Video n Image Stride Register */ | ||
56 | #define VNMB_REG(m) (0x30 + ((m) << 2)) /* Video n Memory Base m Register */ | ||
57 | #define VNIE_REG 0x40 /* Video n Interrupt Enable Register */ | ||
58 | #define VNINTS_REG 0x44 /* Video n Interrupt Status Register */ | ||
59 | #define VNSI_REG 0x48 /* Video n Scanline Interrupt Register */ | ||
60 | #define VNMTC_REG 0x4C /* Video n Memory Transfer Control Register */ | ||
61 | #define VNYS_REG 0x50 /* Video n Y Scale Register */ | ||
62 | #define VNXS_REG 0x54 /* Video n X Scale Register */ | ||
63 | #define VNDMR_REG 0x58 /* Video n Data Mode Register */ | ||
64 | #define VNDMR2_REG 0x5C /* Video n Data Mode Register 2 */ | ||
65 | #define VNUVAOF_REG 0x60 /* Video n UV Address Offset Register */ | ||
66 | #define VNC1A_REG 0x80 /* Video n Coefficient Set C1A Register */ | ||
67 | #define VNC1B_REG 0x84 /* Video n Coefficient Set C1B Register */ | ||
68 | #define VNC1C_REG 0x88 /* Video n Coefficient Set C1C Register */ | ||
69 | #define VNC2A_REG 0x90 /* Video n Coefficient Set C2A Register */ | ||
70 | #define VNC2B_REG 0x94 /* Video n Coefficient Set C2B Register */ | ||
71 | #define VNC2C_REG 0x98 /* Video n Coefficient Set C2C Register */ | ||
72 | #define VNC3A_REG 0xA0 /* Video n Coefficient Set C3A Register */ | ||
73 | #define VNC3B_REG 0xA4 /* Video n Coefficient Set C3B Register */ | ||
74 | #define VNC3C_REG 0xA8 /* Video n Coefficient Set C3C Register */ | ||
75 | #define VNC4A_REG 0xB0 /* Video n Coefficient Set C4A Register */ | ||
76 | #define VNC4B_REG 0xB4 /* Video n Coefficient Set C4B Register */ | ||
77 | #define VNC4C_REG 0xB8 /* Video n Coefficient Set C4C Register */ | ||
78 | #define VNC5A_REG 0xC0 /* Video n Coefficient Set C5A Register */ | ||
79 | #define VNC5B_REG 0xC4 /* Video n Coefficient Set C5B Register */ | ||
80 | #define VNC5C_REG 0xC8 /* Video n Coefficient Set C5C Register */ | ||
81 | #define VNC6A_REG 0xD0 /* Video n Coefficient Set C6A Register */ | ||
82 | #define VNC6B_REG 0xD4 /* Video n Coefficient Set C6B Register */ | ||
83 | #define VNC6C_REG 0xD8 /* Video n Coefficient Set C6C Register */ | ||
84 | #define VNC7A_REG 0xE0 /* Video n Coefficient Set C7A Register */ | ||
85 | #define VNC7B_REG 0xE4 /* Video n Coefficient Set C7B Register */ | ||
86 | #define VNC7C_REG 0xE8 /* Video n Coefficient Set C7C Register */ | ||
87 | #define VNC8A_REG 0xF0 /* Video n Coefficient Set C8A Register */ | ||
88 | #define VNC8B_REG 0xF4 /* Video n Coefficient Set C8B Register */ | ||
89 | #define VNC8C_REG 0xF8 /* Video n Coefficient Set C8C Register */ | ||
90 | |||
91 | /* Register bit fields for R-Car VIN */ | ||
92 | /* Video n Main Control Register bits */ | ||
93 | #define VNMC_FOC (1 << 21) | ||
94 | #define VNMC_YCAL (1 << 19) | ||
95 | #define VNMC_INF_YUV8_BT656 (0 << 16) | ||
96 | #define VNMC_INF_YUV8_BT601 (1 << 16) | ||
97 | #define VNMC_INF_YUV10_BT656 (2 << 16) | ||
98 | #define VNMC_INF_YUV10_BT601 (3 << 16) | ||
99 | #define VNMC_INF_YUV16 (5 << 16) | ||
100 | #define VNMC_INF_RGB888 (6 << 16) | ||
101 | #define VNMC_VUP (1 << 10) | ||
102 | #define VNMC_IM_ODD (0 << 3) | ||
103 | #define VNMC_IM_ODD_EVEN (1 << 3) | ||
104 | #define VNMC_IM_EVEN (2 << 3) | ||
105 | #define VNMC_IM_FULL (3 << 3) | ||
106 | #define VNMC_BPS (1 << 1) | ||
107 | #define VNMC_ME (1 << 0) | ||
108 | |||
109 | /* Video n Module Status Register bits */ | ||
110 | #define VNMS_FBS_MASK (3 << 3) | ||
111 | #define VNMS_FBS_SHIFT 3 | ||
112 | #define VNMS_AV (1 << 1) | ||
113 | #define VNMS_CA (1 << 0) | ||
114 | |||
115 | /* Video n Frame Capture Register bits */ | ||
116 | #define VNFC_C_FRAME (1 << 1) | ||
117 | #define VNFC_S_FRAME (1 << 0) | ||
118 | |||
119 | /* Video n Interrupt Enable Register bits */ | ||
120 | #define VNIE_FIE (1 << 4) | ||
121 | #define VNIE_EFE (1 << 1) | ||
122 | |||
123 | /* Video n Data Mode Register bits */ | ||
124 | #define VNDMR_EXRGB (1 << 8) | ||
125 | #define VNDMR_BPSM (1 << 4) | ||
126 | #define VNDMR_DTMD_YCSEP (1 << 1) | ||
127 | #define VNDMR_DTMD_ARGB (1 << 0) | ||
128 | |||
129 | /* Video n Data Mode Register 2 bits */ | ||
130 | #define VNDMR2_VPS (1 << 30) | ||
131 | #define VNDMR2_HPS (1 << 29) | ||
132 | #define VNDMR2_FTEV (1 << 17) | ||
133 | #define VNDMR2_VLV(n) ((n & 0xf) << 12) | ||
134 | |||
135 | #define VIN_MAX_WIDTH 2048 | ||
136 | #define VIN_MAX_HEIGHT 2048 | ||
137 | |||
138 | #define TIMEOUT_MS 100 | ||
139 | |||
140 | #define RCAR_VIN_HSYNC_ACTIVE_LOW (1 << 0) | ||
141 | #define RCAR_VIN_VSYNC_ACTIVE_LOW (1 << 1) | ||
142 | #define RCAR_VIN_BT601 (1 << 2) | ||
143 | #define RCAR_VIN_BT656 (1 << 3) | ||
144 | |||
145 | enum chip_id { | ||
146 | RCAR_GEN3, | ||
147 | RCAR_GEN2, | ||
148 | RCAR_H1, | ||
149 | RCAR_M1, | ||
150 | RCAR_E1, | ||
151 | }; | ||
152 | |||
153 | struct vin_coeff { | ||
154 | unsigned short xs_value; | ||
155 | u32 coeff_set[24]; | ||
156 | }; | ||
157 | |||
158 | static const struct vin_coeff vin_coeff_set[] = { | ||
159 | { 0x0000, { | ||
160 | 0x00000000, 0x00000000, 0x00000000, | ||
161 | 0x00000000, 0x00000000, 0x00000000, | ||
162 | 0x00000000, 0x00000000, 0x00000000, | ||
163 | 0x00000000, 0x00000000, 0x00000000, | ||
164 | 0x00000000, 0x00000000, 0x00000000, | ||
165 | 0x00000000, 0x00000000, 0x00000000, | ||
166 | 0x00000000, 0x00000000, 0x00000000, | ||
167 | 0x00000000, 0x00000000, 0x00000000 }, | ||
168 | }, | ||
169 | { 0x1000, { | ||
170 | 0x000fa400, 0x000fa400, 0x09625902, | ||
171 | 0x000003f8, 0x00000403, 0x3de0d9f0, | ||
172 | 0x001fffed, 0x00000804, 0x3cc1f9c3, | ||
173 | 0x001003de, 0x00000c01, 0x3cb34d7f, | ||
174 | 0x002003d2, 0x00000c00, 0x3d24a92d, | ||
175 | 0x00200bca, 0x00000bff, 0x3df600d2, | ||
176 | 0x002013cc, 0x000007ff, 0x3ed70c7e, | ||
177 | 0x00100fde, 0x00000000, 0x3f87c036 }, | ||
178 | }, | ||
179 | { 0x1200, { | ||
180 | 0x002ffff1, 0x002ffff1, 0x02a0a9c8, | ||
181 | 0x002003e7, 0x001ffffa, 0x000185bc, | ||
182 | 0x002007dc, 0x000003ff, 0x3e52859c, | ||
183 | 0x00200bd4, 0x00000002, 0x3d53996b, | ||
184 | 0x00100fd0, 0x00000403, 0x3d04ad2d, | ||
185 | 0x00000bd5, 0x00000403, 0x3d35ace7, | ||
186 | 0x3ff003e4, 0x00000801, 0x3dc674a1, | ||
187 | 0x3fffe800, 0x00000800, 0x3e76f461 }, | ||
188 | }, | ||
189 | { 0x1400, { | ||
190 | 0x00100be3, 0x00100be3, 0x04d1359a, | ||
191 | 0x00000fdb, 0x002003ed, 0x0211fd93, | ||
192 | 0x00000fd6, 0x002003f4, 0x0002d97b, | ||
193 | 0x000007d6, 0x002ffffb, 0x3e93b956, | ||
194 | 0x3ff003da, 0x001003ff, 0x3db49926, | ||
195 | 0x3fffefe9, 0x00100001, 0x3d655cee, | ||
196 | 0x3fffd400, 0x00000003, 0x3d65f4b6, | ||
197 | 0x000fb421, 0x00000402, 0x3dc6547e }, | ||
198 | }, | ||
199 | { 0x1600, { | ||
200 | 0x00000bdd, 0x00000bdd, 0x06519578, | ||
201 | 0x3ff007da, 0x00000be3, 0x03c24973, | ||
202 | 0x3ff003d9, 0x00000be9, 0x01b30d5f, | ||
203 | 0x3ffff7df, 0x001003f1, 0x0003c542, | ||
204 | 0x000fdfec, 0x001003f7, 0x3ec4711d, | ||
205 | 0x000fc400, 0x002ffffd, 0x3df504f1, | ||
206 | 0x001fa81a, 0x002ffc00, 0x3d957cc2, | ||
207 | 0x002f8c3c, 0x00100000, 0x3db5c891 }, | ||
208 | }, | ||
209 | { 0x1800, { | ||
210 | 0x3ff003dc, 0x3ff003dc, 0x0791e558, | ||
211 | 0x000ff7dd, 0x3ff007de, 0x05328554, | ||
212 | 0x000fe7e3, 0x3ff00be2, 0x03232546, | ||
213 | 0x000fd7ee, 0x000007e9, 0x0143bd30, | ||
214 | 0x001fb800, 0x000007ee, 0x00044511, | ||
215 | 0x002fa015, 0x000007f4, 0x3ef4bcee, | ||
216 | 0x002f8832, 0x001003f9, 0x3e4514c7, | ||
217 | 0x001f7853, 0x001003fd, 0x3de54c9f }, | ||
218 | }, | ||
219 | { 0x1a00, { | ||
220 | 0x000fefe0, 0x000fefe0, 0x08721d3c, | ||
221 | 0x001fdbe7, 0x000ffbde, 0x0652a139, | ||
222 | 0x001fcbf0, 0x000003df, 0x0463292e, | ||
223 | 0x002fb3ff, 0x3ff007e3, 0x0293a91d, | ||
224 | 0x002f9c12, 0x3ff00be7, 0x01241905, | ||
225 | 0x001f8c29, 0x000007ed, 0x3fe470eb, | ||
226 | 0x000f7c46, 0x000007f2, 0x3f04b8ca, | ||
227 | 0x3fef7865, 0x000007f6, 0x3e74e4a8 }, | ||
228 | }, | ||
229 | { 0x1c00, { | ||
230 | 0x001fd3e9, 0x001fd3e9, 0x08f23d26, | ||
231 | 0x002fbff3, 0x001fe3e4, 0x0712ad23, | ||
232 | 0x002fa800, 0x000ff3e0, 0x05631d1b, | ||
233 | 0x001f9810, 0x000ffbe1, 0x03b3890d, | ||
234 | 0x000f8c23, 0x000003e3, 0x0233e8fa, | ||
235 | 0x3fef843b, 0x000003e7, 0x00f430e4, | ||
236 | 0x3fbf8456, 0x3ff00bea, 0x00046cc8, | ||
237 | 0x3f8f8c72, 0x3ff00bef, 0x3f3490ac }, | ||
238 | }, | ||
239 | { 0x1e00, { | ||
240 | 0x001fbbf4, 0x001fbbf4, 0x09425112, | ||
241 | 0x001fa800, 0x002fc7ed, 0x0792b110, | ||
242 | 0x000f980e, 0x001fdbe6, 0x0613110a, | ||
243 | 0x3fff8c20, 0x001fe7e3, 0x04a368fd, | ||
244 | 0x3fcf8c33, 0x000ff7e2, 0x0343b8ed, | ||
245 | 0x3f9f8c4a, 0x000fffe3, 0x0203f8da, | ||
246 | 0x3f5f9c61, 0x000003e6, 0x00e428c5, | ||
247 | 0x3f1fb07b, 0x000003eb, 0x3fe440af }, | ||
248 | }, | ||
249 | { 0x2000, { | ||
250 | 0x000fa400, 0x000fa400, 0x09625902, | ||
251 | 0x3fff980c, 0x001fb7f5, 0x0812b0ff, | ||
252 | 0x3fdf901c, 0x001fc7ed, 0x06b2fcfa, | ||
253 | 0x3faf902d, 0x001fd3e8, 0x055348f1, | ||
254 | 0x3f7f983f, 0x001fe3e5, 0x04038ce3, | ||
255 | 0x3f3fa454, 0x001fefe3, 0x02e3c8d1, | ||
256 | 0x3f0fb86a, 0x001ff7e4, 0x01c3e8c0, | ||
257 | 0x3ecfd880, 0x000fffe6, 0x00c404ac }, | ||
258 | }, | ||
259 | { 0x2200, { | ||
260 | 0x3fdf9c0b, 0x3fdf9c0b, 0x09725cf4, | ||
261 | 0x3fbf9818, 0x3fffa400, 0x0842a8f1, | ||
262 | 0x3f8f9827, 0x000fb3f7, 0x0702f0ec, | ||
263 | 0x3f5fa037, 0x000fc3ef, 0x05d330e4, | ||
264 | 0x3f2fac49, 0x001fcfea, 0x04a364d9, | ||
265 | 0x3effc05c, 0x001fdbe7, 0x038394ca, | ||
266 | 0x3ecfdc6f, 0x001fe7e6, 0x0273b0bb, | ||
267 | 0x3ea00083, 0x001fefe6, 0x0183c0a9 }, | ||
268 | }, | ||
269 | { 0x2400, { | ||
270 | 0x3f9fa014, 0x3f9fa014, 0x098260e6, | ||
271 | 0x3f7f9c23, 0x3fcf9c0a, 0x08629ce5, | ||
272 | 0x3f4fa431, 0x3fefa400, 0x0742d8e1, | ||
273 | 0x3f1fb440, 0x3fffb3f8, 0x062310d9, | ||
274 | 0x3eefc850, 0x000fbbf2, 0x050340d0, | ||
275 | 0x3ecfe062, 0x000fcbec, 0x041364c2, | ||
276 | 0x3ea00073, 0x001fd3ea, 0x03037cb5, | ||
277 | 0x3e902086, 0x001fdfe8, 0x022388a5 }, | ||
278 | }, | ||
279 | { 0x2600, { | ||
280 | 0x3f5fa81e, 0x3f5fa81e, 0x096258da, | ||
281 | 0x3f3fac2b, 0x3f8fa412, 0x088290d8, | ||
282 | 0x3f0fbc38, 0x3fafa408, 0x0772c8d5, | ||
283 | 0x3eefcc47, 0x3fcfa800, 0x0672f4ce, | ||
284 | 0x3ecfe456, 0x3fefaffa, 0x05531cc6, | ||
285 | 0x3eb00066, 0x3fffbbf3, 0x047334bb, | ||
286 | 0x3ea01c77, 0x000fc7ee, 0x039348ae, | ||
287 | 0x3ea04486, 0x000fd3eb, 0x02b350a1 }, | ||
288 | }, | ||
289 | { 0x2800, { | ||
290 | 0x3f2fb426, 0x3f2fb426, 0x094250ce, | ||
291 | 0x3f0fc032, 0x3f4fac1b, 0x086284cd, | ||
292 | 0x3eefd040, 0x3f7fa811, 0x0782acc9, | ||
293 | 0x3ecfe84c, 0x3f9fa807, 0x06a2d8c4, | ||
294 | 0x3eb0005b, 0x3fbfac00, 0x05b2f4bc, | ||
295 | 0x3eb0186a, 0x3fdfb3fa, 0x04c308b4, | ||
296 | 0x3eb04077, 0x3fefbbf4, 0x03f31ca8, | ||
297 | 0x3ec06884, 0x000fbff2, 0x03031c9e }, | ||
298 | }, | ||
299 | { 0x2a00, { | ||
300 | 0x3f0fc42d, 0x3f0fc42d, 0x090240c4, | ||
301 | 0x3eefd439, 0x3f2fb822, 0x08526cc2, | ||
302 | 0x3edfe845, 0x3f4fb018, 0x078294bf, | ||
303 | 0x3ec00051, 0x3f6fac0f, 0x06b2b4bb, | ||
304 | 0x3ec0185f, 0x3f8fac07, 0x05e2ccb4, | ||
305 | 0x3ec0386b, 0x3fafac00, 0x0502e8ac, | ||
306 | 0x3ed05c77, 0x3fcfb3fb, 0x0432f0a3, | ||
307 | 0x3ef08482, 0x3fdfbbf6, 0x0372f898 }, | ||
308 | }, | ||
309 | { 0x2c00, { | ||
310 | 0x3eefdc31, 0x3eefdc31, 0x08e238b8, | ||
311 | 0x3edfec3d, 0x3f0fc828, 0x082258b9, | ||
312 | 0x3ed00049, 0x3f1fc01e, 0x077278b6, | ||
313 | 0x3ed01455, 0x3f3fb815, 0x06c294b2, | ||
314 | 0x3ed03460, 0x3f5fb40d, 0x0602acac, | ||
315 | 0x3ef0506c, 0x3f7fb006, 0x0542c0a4, | ||
316 | 0x3f107476, 0x3f9fb400, 0x0472c89d, | ||
317 | 0x3f309c80, 0x3fbfb7fc, 0x03b2cc94 }, | ||
318 | }, | ||
319 | { 0x2e00, { | ||
320 | 0x3eefec37, 0x3eefec37, 0x088220b0, | ||
321 | 0x3ee00041, 0x3effdc2d, 0x07f244ae, | ||
322 | 0x3ee0144c, 0x3f0fd023, 0x07625cad, | ||
323 | 0x3ef02c57, 0x3f1fc81a, 0x06c274a9, | ||
324 | 0x3f004861, 0x3f3fbc13, 0x060288a6, | ||
325 | 0x3f20686b, 0x3f5fb80c, 0x05529c9e, | ||
326 | 0x3f408c74, 0x3f6fb805, 0x04b2ac96, | ||
327 | 0x3f80ac7e, 0x3f8fb800, 0x0402ac8e }, | ||
328 | }, | ||
329 | { 0x3000, { | ||
330 | 0x3ef0003a, 0x3ef0003a, 0x084210a6, | ||
331 | 0x3ef01045, 0x3effec32, 0x07b228a7, | ||
332 | 0x3f00284e, 0x3f0fdc29, 0x073244a4, | ||
333 | 0x3f104058, 0x3f0fd420, 0x06a258a2, | ||
334 | 0x3f305c62, 0x3f2fc818, 0x0612689d, | ||
335 | 0x3f508069, 0x3f3fc011, 0x05728496, | ||
336 | 0x3f80a072, 0x3f4fc00a, 0x04d28c90, | ||
337 | 0x3fc0c07b, 0x3f6fbc04, 0x04429088 }, | ||
338 | }, | ||
339 | { 0x3200, { | ||
340 | 0x3f00103e, 0x3f00103e, 0x07f1fc9e, | ||
341 | 0x3f102447, 0x3f000035, 0x0782149d, | ||
342 | 0x3f203c4f, 0x3f0ff02c, 0x07122c9c, | ||
343 | 0x3f405458, 0x3f0fe424, 0x06924099, | ||
344 | 0x3f607061, 0x3f1fd41d, 0x06024c97, | ||
345 | 0x3f909068, 0x3f2fcc16, 0x05726490, | ||
346 | 0x3fc0b070, 0x3f3fc80f, 0x04f26c8a, | ||
347 | 0x0000d077, 0x3f4fc409, 0x04627484 }, | ||
348 | }, | ||
349 | { 0x3400, { | ||
350 | 0x3f202040, 0x3f202040, 0x07a1e898, | ||
351 | 0x3f303449, 0x3f100c38, 0x0741fc98, | ||
352 | 0x3f504c50, 0x3f10002f, 0x06e21495, | ||
353 | 0x3f706459, 0x3f1ff028, 0x06722492, | ||
354 | 0x3fa08060, 0x3f1fe421, 0x05f2348f, | ||
355 | 0x3fd09c67, 0x3f1fdc19, 0x05824c89, | ||
356 | 0x0000bc6e, 0x3f2fd014, 0x04f25086, | ||
357 | 0x0040dc74, 0x3f3fcc0d, 0x04825c7f }, | ||
358 | }, | ||
359 | { 0x3600, { | ||
360 | 0x3f403042, 0x3f403042, 0x0761d890, | ||
361 | 0x3f504848, 0x3f301c3b, 0x0701f090, | ||
362 | 0x3f805c50, 0x3f200c33, 0x06a2008f, | ||
363 | 0x3fa07458, 0x3f10002b, 0x06520c8d, | ||
364 | 0x3fd0905e, 0x3f1ff424, 0x05e22089, | ||
365 | 0x0000ac65, 0x3f1fe81d, 0x05823483, | ||
366 | 0x0030cc6a, 0x3f2fdc18, 0x04f23c81, | ||
367 | 0x0080e871, 0x3f2fd412, 0x0482407c }, | ||
368 | }, | ||
369 | { 0x3800, { | ||
370 | 0x3f604043, 0x3f604043, 0x0721c88a, | ||
371 | 0x3f80544a, 0x3f502c3c, 0x06d1d88a, | ||
372 | 0x3fb06851, 0x3f301c35, 0x0681e889, | ||
373 | 0x3fd08456, 0x3f30082f, 0x0611fc88, | ||
374 | 0x00009c5d, 0x3f200027, 0x05d20884, | ||
375 | 0x0030b863, 0x3f2ff421, 0x05621880, | ||
376 | 0x0070d468, 0x3f2fe81b, 0x0502247c, | ||
377 | 0x00c0ec6f, 0x3f2fe015, 0x04a22877 }, | ||
378 | }, | ||
379 | { 0x3a00, { | ||
380 | 0x3f904c44, 0x3f904c44, 0x06e1b884, | ||
381 | 0x3fb0604a, 0x3f70383e, 0x0691c885, | ||
382 | 0x3fe07451, 0x3f502c36, 0x0661d483, | ||
383 | 0x00009055, 0x3f401831, 0x0601ec81, | ||
384 | 0x0030a85b, 0x3f300c2a, 0x05b1f480, | ||
385 | 0x0070c061, 0x3f300024, 0x0562047a, | ||
386 | 0x00b0d867, 0x3f3ff41e, 0x05020c77, | ||
387 | 0x00f0f46b, 0x3f2fec19, 0x04a21474 }, | ||
388 | }, | ||
389 | { 0x3c00, { | ||
390 | 0x3fb05c43, 0x3fb05c43, 0x06c1b07e, | ||
391 | 0x3fe06c4b, 0x3f902c3f, 0x0681c081, | ||
392 | 0x0000844f, 0x3f703838, 0x0631cc7d, | ||
393 | 0x00309855, 0x3f602433, 0x05d1d47e, | ||
394 | 0x0060b459, 0x3f50142e, 0x0581e47b, | ||
395 | 0x00a0c85f, 0x3f400828, 0x0531f078, | ||
396 | 0x00e0e064, 0x3f300021, 0x0501fc73, | ||
397 | 0x00b0fc6a, 0x3f3ff41d, 0x04a20873 }, | ||
398 | }, | ||
399 | { 0x3e00, { | ||
400 | 0x3fe06444, 0x3fe06444, 0x0681a07a, | ||
401 | 0x00007849, 0x3fc0503f, 0x0641b07a, | ||
402 | 0x0020904d, 0x3fa0403a, 0x05f1c07a, | ||
403 | 0x0060a453, 0x3f803034, 0x05c1c878, | ||
404 | 0x0090b858, 0x3f70202f, 0x0571d477, | ||
405 | 0x00d0d05d, 0x3f501829, 0x0531e073, | ||
406 | 0x0110e462, 0x3f500825, 0x04e1e471, | ||
407 | 0x01510065, 0x3f40001f, 0x04a1f06d }, | ||
408 | }, | ||
409 | { 0x4000, { | ||
410 | 0x00007044, 0x00007044, 0x06519476, | ||
411 | 0x00208448, 0x3fe05c3f, 0x0621a476, | ||
412 | 0x0050984d, 0x3fc04c3a, 0x05e1b075, | ||
413 | 0x0080ac52, 0x3fa03c35, 0x05a1b875, | ||
414 | 0x00c0c056, 0x3f803030, 0x0561c473, | ||
415 | 0x0100d45b, 0x3f70202b, 0x0521d46f, | ||
416 | 0x0140e860, 0x3f601427, 0x04d1d46e, | ||
417 | 0x01810064, 0x3f500822, 0x0491dc6b }, | ||
418 | }, | ||
419 | { 0x5000, { | ||
420 | 0x0110a442, 0x0110a442, 0x0551545e, | ||
421 | 0x0140b045, 0x00e0983f, 0x0531585f, | ||
422 | 0x0160c047, 0x00c08c3c, 0x0511645e, | ||
423 | 0x0190cc4a, 0x00908039, 0x04f1685f, | ||
424 | 0x01c0dc4c, 0x00707436, 0x04d1705e, | ||
425 | 0x0200e850, 0x00506833, 0x04b1785b, | ||
426 | 0x0230f453, 0x00305c30, 0x0491805a, | ||
427 | 0x02710056, 0x0010542d, 0x04718059 }, | ||
428 | }, | ||
429 | { 0x6000, { | ||
430 | 0x01c0bc40, 0x01c0bc40, 0x04c13052, | ||
431 | 0x01e0c841, 0x01a0b43d, 0x04c13851, | ||
432 | 0x0210cc44, 0x0180a83c, 0x04a13453, | ||
433 | 0x0230d845, 0x0160a03a, 0x04913c52, | ||
434 | 0x0260e047, 0x01409838, 0x04714052, | ||
435 | 0x0280ec49, 0x01208c37, 0x04514c50, | ||
436 | 0x02b0f44b, 0x01008435, 0x04414c50, | ||
437 | 0x02d1004c, 0x00e07c33, 0x0431544f }, | ||
438 | }, | ||
439 | { 0x7000, { | ||
440 | 0x0230c83e, 0x0230c83e, 0x04711c4c, | ||
441 | 0x0250d03f, 0x0210c43c, 0x0471204b, | ||
442 | 0x0270d840, 0x0200b83c, 0x0451244b, | ||
443 | 0x0290dc42, 0x01e0b43a, 0x0441244c, | ||
444 | 0x02b0e443, 0x01c0b038, 0x0441284b, | ||
445 | 0x02d0ec44, 0x01b0a438, 0x0421304a, | ||
446 | 0x02f0f445, 0x0190a036, 0x04213449, | ||
447 | 0x0310f847, 0x01709c34, 0x04213848 }, | ||
448 | }, | ||
449 | { 0x8000, { | ||
450 | 0x0280d03d, 0x0280d03d, 0x04310c48, | ||
451 | 0x02a0d43e, 0x0270c83c, 0x04311047, | ||
452 | 0x02b0dc3e, 0x0250c83a, 0x04311447, | ||
453 | 0x02d0e040, 0x0240c03a, 0x04211446, | ||
454 | 0x02e0e840, 0x0220bc39, 0x04111847, | ||
455 | 0x0300e842, 0x0210b438, 0x04012445, | ||
456 | 0x0310f043, 0x0200b037, 0x04012045, | ||
457 | 0x0330f444, 0x01e0ac36, 0x03f12445 }, | ||
458 | }, | ||
459 | { 0xefff, { | ||
460 | 0x0340dc3a, 0x0340dc3a, 0x03b0ec40, | ||
461 | 0x0340e03a, 0x0330e039, 0x03c0f03e, | ||
462 | 0x0350e03b, 0x0330dc39, 0x03c0ec3e, | ||
463 | 0x0350e43a, 0x0320dc38, 0x03c0f43e, | ||
464 | 0x0360e43b, 0x0320d839, 0x03b0f03e, | ||
465 | 0x0360e83b, 0x0310d838, 0x03c0fc3b, | ||
466 | 0x0370e83b, 0x0310d439, 0x03a0f83d, | ||
467 | 0x0370e83c, 0x0300d438, 0x03b0fc3c }, | ||
468 | } | ||
469 | }; | ||
470 | |||
471 | enum rcar_vin_state { | ||
472 | STOPPED = 0, | ||
473 | RUNNING, | ||
474 | STOPPING, | ||
475 | }; | ||
476 | |||
477 | struct rcar_vin_priv { | ||
478 | void __iomem *base; | ||
479 | spinlock_t lock; | ||
480 | int sequence; | ||
481 | /* State of the VIN module in capturing mode */ | ||
482 | enum rcar_vin_state state; | ||
483 | struct soc_camera_host ici; | ||
484 | struct list_head capture; | ||
485 | #define MAX_BUFFER_NUM 3 | ||
486 | struct vb2_v4l2_buffer *queue_buf[MAX_BUFFER_NUM]; | ||
487 | enum v4l2_field field; | ||
488 | unsigned int pdata_flags; | ||
489 | unsigned int vb_count; | ||
490 | unsigned int nr_hw_slots; | ||
491 | bool request_to_stop; | ||
492 | struct completion capture_stop; | ||
493 | enum chip_id chip; | ||
494 | }; | ||
495 | |||
496 | #define is_continuous_transfer(priv) (priv->vb_count > MAX_BUFFER_NUM) | ||
497 | |||
498 | struct rcar_vin_buffer { | ||
499 | struct vb2_v4l2_buffer vb; | ||
500 | struct list_head list; | ||
501 | }; | ||
502 | |||
503 | #define to_buf_list(vb2_buffer) (&container_of(vb2_buffer, \ | ||
504 | struct rcar_vin_buffer, \ | ||
505 | vb)->list) | ||
506 | |||
507 | struct rcar_vin_cam { | ||
508 | /* VIN offsets within the camera output, before the VIN scaler */ | ||
509 | unsigned int vin_left; | ||
510 | unsigned int vin_top; | ||
511 | /* Client output, as seen by the VIN */ | ||
512 | unsigned int width; | ||
513 | unsigned int height; | ||
514 | /* User window from S_FMT */ | ||
515 | unsigned int out_width; | ||
516 | unsigned int out_height; | ||
517 | /* | ||
518 | * User window from S_CROP / G_CROP, produced by client cropping and | ||
519 | * scaling, VIN scaling and VIN cropping, mapped back onto the client | ||
520 | * input window | ||
521 | */ | ||
522 | struct v4l2_rect subrect; | ||
523 | /* Camera cropping rectangle */ | ||
524 | struct v4l2_rect rect; | ||
525 | const struct soc_mbus_pixelfmt *extra_fmt; | ||
526 | }; | ||
527 | |||
528 | /* | ||
529 | * .queue_setup() is called to check whether the driver can accept the requested | ||
530 | * number of buffers and to fill in plane sizes for the current frame format if | ||
531 | * required | ||
532 | */ | ||
533 | static int rcar_vin_videobuf_setup(struct vb2_queue *vq, | ||
534 | unsigned int *count, | ||
535 | unsigned int *num_planes, | ||
536 | unsigned int sizes[], struct device *alloc_devs[]) | ||
537 | { | ||
538 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | ||
539 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
540 | struct rcar_vin_priv *priv = ici->priv; | ||
541 | |||
542 | if (!vq->num_buffers) | ||
543 | priv->sequence = 0; | ||
544 | |||
545 | if (!*count) | ||
546 | *count = 2; | ||
547 | priv->vb_count = *count; | ||
548 | |||
549 | /* Number of hardware slots */ | ||
550 | if (is_continuous_transfer(priv)) | ||
551 | priv->nr_hw_slots = MAX_BUFFER_NUM; | ||
552 | else | ||
553 | priv->nr_hw_slots = 1; | ||
554 | |||
555 | if (*num_planes) | ||
556 | return sizes[0] < icd->sizeimage ? -EINVAL : 0; | ||
557 | |||
558 | sizes[0] = icd->sizeimage; | ||
559 | *num_planes = 1; | ||
560 | |||
561 | dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); | ||
562 | |||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | static int rcar_vin_setup(struct rcar_vin_priv *priv) | ||
567 | { | ||
568 | struct soc_camera_device *icd = priv->ici.icd; | ||
569 | struct rcar_vin_cam *cam = icd->host_priv; | ||
570 | u32 vnmc, dmr, interrupts; | ||
571 | bool progressive = false, output_is_yuv = false, input_is_yuv = false; | ||
572 | |||
573 | switch (priv->field) { | ||
574 | case V4L2_FIELD_TOP: | ||
575 | vnmc = VNMC_IM_ODD; | ||
576 | break; | ||
577 | case V4L2_FIELD_BOTTOM: | ||
578 | vnmc = VNMC_IM_EVEN; | ||
579 | break; | ||
580 | case V4L2_FIELD_INTERLACED: | ||
581 | case V4L2_FIELD_INTERLACED_TB: | ||
582 | vnmc = VNMC_IM_FULL; | ||
583 | break; | ||
584 | case V4L2_FIELD_INTERLACED_BT: | ||
585 | vnmc = VNMC_IM_FULL | VNMC_FOC; | ||
586 | break; | ||
587 | case V4L2_FIELD_NONE: | ||
588 | if (is_continuous_transfer(priv)) { | ||
589 | vnmc = VNMC_IM_ODD_EVEN; | ||
590 | progressive = true; | ||
591 | } else { | ||
592 | vnmc = VNMC_IM_ODD; | ||
593 | } | ||
594 | break; | ||
595 | default: | ||
596 | vnmc = VNMC_IM_ODD; | ||
597 | break; | ||
598 | } | ||
599 | |||
600 | /* input interface */ | ||
601 | switch (icd->current_fmt->code) { | ||
602 | case MEDIA_BUS_FMT_YUYV8_1X16: | ||
603 | /* BT.601/BT.1358 16bit YCbCr422 */ | ||
604 | vnmc |= VNMC_INF_YUV16; | ||
605 | input_is_yuv = true; | ||
606 | break; | ||
607 | case MEDIA_BUS_FMT_YUYV8_2X8: | ||
608 | /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ | ||
609 | vnmc |= priv->pdata_flags & RCAR_VIN_BT656 ? | ||
610 | VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601; | ||
611 | input_is_yuv = true; | ||
612 | break; | ||
613 | case MEDIA_BUS_FMT_RGB888_1X24: | ||
614 | vnmc |= VNMC_INF_RGB888; | ||
615 | break; | ||
616 | case MEDIA_BUS_FMT_YUYV10_2X10: | ||
617 | /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ | ||
618 | vnmc |= priv->pdata_flags & RCAR_VIN_BT656 ? | ||
619 | VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601; | ||
620 | input_is_yuv = true; | ||
621 | break; | ||
622 | default: | ||
623 | break; | ||
624 | } | ||
625 | |||
626 | /* output format */ | ||
627 | switch (icd->current_fmt->host_fmt->fourcc) { | ||
628 | case V4L2_PIX_FMT_NV16: | ||
629 | iowrite32(ALIGN(cam->width * cam->height, 0x80), | ||
630 | priv->base + VNUVAOF_REG); | ||
631 | dmr = VNDMR_DTMD_YCSEP; | ||
632 | output_is_yuv = true; | ||
633 | break; | ||
634 | case V4L2_PIX_FMT_YUYV: | ||
635 | dmr = VNDMR_BPSM; | ||
636 | output_is_yuv = true; | ||
637 | break; | ||
638 | case V4L2_PIX_FMT_UYVY: | ||
639 | dmr = 0; | ||
640 | output_is_yuv = true; | ||
641 | break; | ||
642 | case V4L2_PIX_FMT_RGB555X: | ||
643 | dmr = VNDMR_DTMD_ARGB; | ||
644 | break; | ||
645 | case V4L2_PIX_FMT_RGB565: | ||
646 | dmr = 0; | ||
647 | break; | ||
648 | case V4L2_PIX_FMT_RGB32: | ||
649 | if (priv->chip != RCAR_GEN2 && priv->chip != RCAR_H1 && | ||
650 | priv->chip != RCAR_E1) | ||
651 | goto e_format; | ||
652 | |||
653 | dmr = VNDMR_EXRGB; | ||
654 | break; | ||
655 | case V4L2_PIX_FMT_ARGB32: | ||
656 | if (priv->chip != RCAR_GEN3) | ||
657 | goto e_format; | ||
658 | |||
659 | dmr = VNDMR_EXRGB | VNDMR_DTMD_ARGB; | ||
660 | break; | ||
661 | default: | ||
662 | goto e_format; | ||
663 | } | ||
664 | |||
665 | /* Always update on field change */ | ||
666 | vnmc |= VNMC_VUP; | ||
667 | |||
668 | /* If input and output use the same colorspace, use bypass mode */ | ||
669 | if (input_is_yuv == output_is_yuv) | ||
670 | vnmc |= VNMC_BPS; | ||
671 | |||
672 | /* progressive or interlaced mode */ | ||
673 | interrupts = progressive ? VNIE_FIE : VNIE_EFE; | ||
674 | |||
675 | /* ack interrupts */ | ||
676 | iowrite32(interrupts, priv->base + VNINTS_REG); | ||
677 | /* enable interrupts */ | ||
678 | iowrite32(interrupts, priv->base + VNIE_REG); | ||
679 | /* start capturing */ | ||
680 | iowrite32(dmr, priv->base + VNDMR_REG); | ||
681 | iowrite32(vnmc | VNMC_ME, priv->base + VNMC_REG); | ||
682 | |||
683 | return 0; | ||
684 | |||
685 | e_format: | ||
686 | dev_warn(icd->parent, "Invalid fourcc format (0x%x)\n", | ||
687 | icd->current_fmt->host_fmt->fourcc); | ||
688 | return -EINVAL; | ||
689 | } | ||
690 | |||
691 | static void rcar_vin_capture(struct rcar_vin_priv *priv) | ||
692 | { | ||
693 | if (is_continuous_transfer(priv)) | ||
694 | /* Continuous Frame Capture Mode */ | ||
695 | iowrite32(VNFC_C_FRAME, priv->base + VNFC_REG); | ||
696 | else | ||
697 | /* Single Frame Capture Mode */ | ||
698 | iowrite32(VNFC_S_FRAME, priv->base + VNFC_REG); | ||
699 | } | ||
700 | |||
701 | static void rcar_vin_request_capture_stop(struct rcar_vin_priv *priv) | ||
702 | { | ||
703 | priv->state = STOPPING; | ||
704 | |||
705 | /* set continuous & single transfer off */ | ||
706 | iowrite32(0, priv->base + VNFC_REG); | ||
707 | /* disable capture (release DMA buffer), reset */ | ||
708 | iowrite32(ioread32(priv->base + VNMC_REG) & ~VNMC_ME, | ||
709 | priv->base + VNMC_REG); | ||
710 | |||
711 | /* update the status if stopped already */ | ||
712 | if (!(ioread32(priv->base + VNMS_REG) & VNMS_CA)) | ||
713 | priv->state = STOPPED; | ||
714 | } | ||
715 | |||
716 | static int rcar_vin_get_free_hw_slot(struct rcar_vin_priv *priv) | ||
717 | { | ||
718 | int slot; | ||
719 | |||
720 | for (slot = 0; slot < priv->nr_hw_slots; slot++) | ||
721 | if (priv->queue_buf[slot] == NULL) | ||
722 | return slot; | ||
723 | |||
724 | return -1; | ||
725 | } | ||
726 | |||
727 | static int rcar_vin_hw_ready(struct rcar_vin_priv *priv) | ||
728 | { | ||
729 | /* Ensure all HW slots are filled */ | ||
730 | return rcar_vin_get_free_hw_slot(priv) < 0 ? 1 : 0; | ||
731 | } | ||
732 | |||
733 | /* Moves a buffer from the queue to the HW slots */ | ||
734 | static int rcar_vin_fill_hw_slot(struct rcar_vin_priv *priv) | ||
735 | { | ||
736 | struct vb2_v4l2_buffer *vbuf; | ||
737 | dma_addr_t phys_addr_top; | ||
738 | int slot; | ||
739 | |||
740 | if (list_empty(&priv->capture)) | ||
741 | return 0; | ||
742 | |||
743 | /* Find a free HW slot */ | ||
744 | slot = rcar_vin_get_free_hw_slot(priv); | ||
745 | if (slot < 0) | ||
746 | return 0; | ||
747 | |||
748 | vbuf = &list_entry(priv->capture.next, | ||
749 | struct rcar_vin_buffer, list)->vb; | ||
750 | list_del_init(to_buf_list(vbuf)); | ||
751 | priv->queue_buf[slot] = vbuf; | ||
752 | phys_addr_top = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); | ||
753 | iowrite32(phys_addr_top, priv->base + VNMB_REG(slot)); | ||
754 | |||
755 | return 1; | ||
756 | } | ||
757 | |||
758 | static void rcar_vin_videobuf_queue(struct vb2_buffer *vb) | ||
759 | { | ||
760 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
761 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
762 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
763 | struct rcar_vin_priv *priv = ici->priv; | ||
764 | unsigned long size; | ||
765 | |||
766 | size = icd->sizeimage; | ||
767 | |||
768 | if (vb2_plane_size(vb, 0) < size) { | ||
769 | dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n", | ||
770 | vb->index, vb2_plane_size(vb, 0), size); | ||
771 | goto error; | ||
772 | } | ||
773 | |||
774 | vb2_set_plane_payload(vb, 0, size); | ||
775 | |||
776 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | ||
777 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | ||
778 | |||
779 | spin_lock_irq(&priv->lock); | ||
780 | |||
781 | list_add_tail(to_buf_list(vbuf), &priv->capture); | ||
782 | rcar_vin_fill_hw_slot(priv); | ||
783 | |||
784 | /* If we weren't running, and have enough buffers, start capturing! */ | ||
785 | if (priv->state != RUNNING && rcar_vin_hw_ready(priv)) { | ||
786 | if (rcar_vin_setup(priv)) { | ||
787 | /* Submit error */ | ||
788 | list_del_init(to_buf_list(vbuf)); | ||
789 | spin_unlock_irq(&priv->lock); | ||
790 | goto error; | ||
791 | } | ||
792 | priv->request_to_stop = false; | ||
793 | init_completion(&priv->capture_stop); | ||
794 | priv->state = RUNNING; | ||
795 | rcar_vin_capture(priv); | ||
796 | } | ||
797 | |||
798 | spin_unlock_irq(&priv->lock); | ||
799 | |||
800 | return; | ||
801 | |||
802 | error: | ||
803 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
804 | } | ||
805 | |||
806 | /* | ||
807 | * Wait for capture to stop and all in-flight buffers to be finished with by | ||
808 | * the video hardware. This must be called under &priv->lock | ||
809 | * | ||
810 | */ | ||
811 | static void rcar_vin_wait_stop_streaming(struct rcar_vin_priv *priv) | ||
812 | { | ||
813 | while (priv->state != STOPPED) { | ||
814 | /* issue stop if running */ | ||
815 | if (priv->state == RUNNING) | ||
816 | rcar_vin_request_capture_stop(priv); | ||
817 | |||
818 | /* wait until capturing has been stopped */ | ||
819 | if (priv->state == STOPPING) { | ||
820 | priv->request_to_stop = true; | ||
821 | spin_unlock_irq(&priv->lock); | ||
822 | if (!wait_for_completion_timeout( | ||
823 | &priv->capture_stop, | ||
824 | msecs_to_jiffies(TIMEOUT_MS))) | ||
825 | priv->state = STOPPED; | ||
826 | spin_lock_irq(&priv->lock); | ||
827 | } | ||
828 | } | ||
829 | } | ||
830 | |||
831 | static void rcar_vin_stop_streaming(struct vb2_queue *vq) | ||
832 | { | ||
833 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | ||
834 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
835 | struct rcar_vin_priv *priv = ici->priv; | ||
836 | struct list_head *buf_head, *tmp; | ||
837 | int i; | ||
838 | |||
839 | spin_lock_irq(&priv->lock); | ||
840 | rcar_vin_wait_stop_streaming(priv); | ||
841 | |||
842 | for (i = 0; i < MAX_BUFFER_NUM; i++) { | ||
843 | if (priv->queue_buf[i]) { | ||
844 | vb2_buffer_done(&priv->queue_buf[i]->vb2_buf, | ||
845 | VB2_BUF_STATE_ERROR); | ||
846 | priv->queue_buf[i] = NULL; | ||
847 | } | ||
848 | } | ||
849 | |||
850 | list_for_each_safe(buf_head, tmp, &priv->capture) { | ||
851 | vb2_buffer_done(&list_entry(buf_head, | ||
852 | struct rcar_vin_buffer, list)->vb.vb2_buf, | ||
853 | VB2_BUF_STATE_ERROR); | ||
854 | list_del_init(buf_head); | ||
855 | } | ||
856 | spin_unlock_irq(&priv->lock); | ||
857 | } | ||
858 | |||
859 | static struct vb2_ops rcar_vin_vb2_ops = { | ||
860 | .queue_setup = rcar_vin_videobuf_setup, | ||
861 | .buf_queue = rcar_vin_videobuf_queue, | ||
862 | .stop_streaming = rcar_vin_stop_streaming, | ||
863 | .wait_prepare = vb2_ops_wait_prepare, | ||
864 | .wait_finish = vb2_ops_wait_finish, | ||
865 | }; | ||
866 | |||
867 | static irqreturn_t rcar_vin_irq(int irq, void *data) | ||
868 | { | ||
869 | struct rcar_vin_priv *priv = data; | ||
870 | u32 int_status; | ||
871 | bool can_run = false, hw_stopped; | ||
872 | int slot; | ||
873 | unsigned int handled = 0; | ||
874 | |||
875 | spin_lock(&priv->lock); | ||
876 | |||
877 | int_status = ioread32(priv->base + VNINTS_REG); | ||
878 | if (!int_status) | ||
879 | goto done; | ||
880 | /* ack interrupts */ | ||
881 | iowrite32(int_status, priv->base + VNINTS_REG); | ||
882 | handled = 1; | ||
883 | |||
884 | /* nothing to do if capture status is 'STOPPED' */ | ||
885 | if (priv->state == STOPPED) | ||
886 | goto done; | ||
887 | |||
888 | hw_stopped = !(ioread32(priv->base + VNMS_REG) & VNMS_CA); | ||
889 | |||
890 | if (!priv->request_to_stop) { | ||
891 | if (is_continuous_transfer(priv)) | ||
892 | slot = (ioread32(priv->base + VNMS_REG) & | ||
893 | VNMS_FBS_MASK) >> VNMS_FBS_SHIFT; | ||
894 | else | ||
895 | slot = 0; | ||
896 | |||
897 | priv->queue_buf[slot]->field = priv->field; | ||
898 | priv->queue_buf[slot]->sequence = priv->sequence++; | ||
899 | priv->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); | ||
900 | vb2_buffer_done(&priv->queue_buf[slot]->vb2_buf, | ||
901 | VB2_BUF_STATE_DONE); | ||
902 | priv->queue_buf[slot] = NULL; | ||
903 | |||
904 | if (priv->state != STOPPING) | ||
905 | can_run = rcar_vin_fill_hw_slot(priv); | ||
906 | |||
907 | if (hw_stopped || !can_run) { | ||
908 | priv->state = STOPPED; | ||
909 | } else if (is_continuous_transfer(priv) && | ||
910 | list_empty(&priv->capture) && | ||
911 | priv->state == RUNNING) { | ||
912 | /* | ||
913 | * The continuous capturing requires an explicit stop | ||
914 | * operation when there is no buffer to be set into | ||
915 | * the VnMBm registers. | ||
916 | */ | ||
917 | rcar_vin_request_capture_stop(priv); | ||
918 | } else { | ||
919 | rcar_vin_capture(priv); | ||
920 | } | ||
921 | |||
922 | } else if (hw_stopped) { | ||
923 | priv->state = STOPPED; | ||
924 | priv->request_to_stop = false; | ||
925 | complete(&priv->capture_stop); | ||
926 | } | ||
927 | |||
928 | done: | ||
929 | spin_unlock(&priv->lock); | ||
930 | |||
931 | return IRQ_RETVAL(handled); | ||
932 | } | ||
933 | |||
934 | static int rcar_vin_add_device(struct soc_camera_device *icd) | ||
935 | { | ||
936 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
937 | struct rcar_vin_priv *priv = ici->priv; | ||
938 | int i; | ||
939 | |||
940 | for (i = 0; i < MAX_BUFFER_NUM; i++) | ||
941 | priv->queue_buf[i] = NULL; | ||
942 | |||
943 | pm_runtime_get_sync(ici->v4l2_dev.dev); | ||
944 | |||
945 | dev_dbg(icd->parent, "R-Car VIN driver attached to camera %d\n", | ||
946 | icd->devnum); | ||
947 | |||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | static void rcar_vin_remove_device(struct soc_camera_device *icd) | ||
952 | { | ||
953 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
954 | struct rcar_vin_priv *priv = ici->priv; | ||
955 | struct vb2_v4l2_buffer *vbuf; | ||
956 | int i; | ||
957 | |||
958 | /* disable capture, disable interrupts */ | ||
959 | iowrite32(ioread32(priv->base + VNMC_REG) & ~VNMC_ME, | ||
960 | priv->base + VNMC_REG); | ||
961 | iowrite32(0, priv->base + VNIE_REG); | ||
962 | |||
963 | priv->state = STOPPED; | ||
964 | priv->request_to_stop = false; | ||
965 | |||
966 | /* make sure active buffer is cancelled */ | ||
967 | spin_lock_irq(&priv->lock); | ||
968 | for (i = 0; i < MAX_BUFFER_NUM; i++) { | ||
969 | vbuf = priv->queue_buf[i]; | ||
970 | if (vbuf) { | ||
971 | list_del_init(to_buf_list(vbuf)); | ||
972 | vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_ERROR); | ||
973 | } | ||
974 | } | ||
975 | spin_unlock_irq(&priv->lock); | ||
976 | |||
977 | pm_runtime_put(ici->v4l2_dev.dev); | ||
978 | |||
979 | dev_dbg(icd->parent, "R-Car VIN driver detached from camera %d\n", | ||
980 | icd->devnum); | ||
981 | } | ||
982 | |||
983 | static void set_coeff(struct rcar_vin_priv *priv, unsigned short xs) | ||
984 | { | ||
985 | int i; | ||
986 | const struct vin_coeff *p_prev_set = NULL; | ||
987 | const struct vin_coeff *p_set = NULL; | ||
988 | |||
989 | /* Look for suitable coefficient values */ | ||
990 | for (i = 0; i < ARRAY_SIZE(vin_coeff_set); i++) { | ||
991 | p_prev_set = p_set; | ||
992 | p_set = &vin_coeff_set[i]; | ||
993 | |||
994 | if (xs < p_set->xs_value) | ||
995 | break; | ||
996 | } | ||
997 | |||
998 | /* Use previous value if its XS value is closer */ | ||
999 | if (p_prev_set && p_set && | ||
1000 | xs - p_prev_set->xs_value < p_set->xs_value - xs) | ||
1001 | p_set = p_prev_set; | ||
1002 | |||
1003 | /* Set coefficient registers */ | ||
1004 | iowrite32(p_set->coeff_set[0], priv->base + VNC1A_REG); | ||
1005 | iowrite32(p_set->coeff_set[1], priv->base + VNC1B_REG); | ||
1006 | iowrite32(p_set->coeff_set[2], priv->base + VNC1C_REG); | ||
1007 | |||
1008 | iowrite32(p_set->coeff_set[3], priv->base + VNC2A_REG); | ||
1009 | iowrite32(p_set->coeff_set[4], priv->base + VNC2B_REG); | ||
1010 | iowrite32(p_set->coeff_set[5], priv->base + VNC2C_REG); | ||
1011 | |||
1012 | iowrite32(p_set->coeff_set[6], priv->base + VNC3A_REG); | ||
1013 | iowrite32(p_set->coeff_set[7], priv->base + VNC3B_REG); | ||
1014 | iowrite32(p_set->coeff_set[8], priv->base + VNC3C_REG); | ||
1015 | |||
1016 | iowrite32(p_set->coeff_set[9], priv->base + VNC4A_REG); | ||
1017 | iowrite32(p_set->coeff_set[10], priv->base + VNC4B_REG); | ||
1018 | iowrite32(p_set->coeff_set[11], priv->base + VNC4C_REG); | ||
1019 | |||
1020 | iowrite32(p_set->coeff_set[12], priv->base + VNC5A_REG); | ||
1021 | iowrite32(p_set->coeff_set[13], priv->base + VNC5B_REG); | ||
1022 | iowrite32(p_set->coeff_set[14], priv->base + VNC5C_REG); | ||
1023 | |||
1024 | iowrite32(p_set->coeff_set[15], priv->base + VNC6A_REG); | ||
1025 | iowrite32(p_set->coeff_set[16], priv->base + VNC6B_REG); | ||
1026 | iowrite32(p_set->coeff_set[17], priv->base + VNC6C_REG); | ||
1027 | |||
1028 | iowrite32(p_set->coeff_set[18], priv->base + VNC7A_REG); | ||
1029 | iowrite32(p_set->coeff_set[19], priv->base + VNC7B_REG); | ||
1030 | iowrite32(p_set->coeff_set[20], priv->base + VNC7C_REG); | ||
1031 | |||
1032 | iowrite32(p_set->coeff_set[21], priv->base + VNC8A_REG); | ||
1033 | iowrite32(p_set->coeff_set[22], priv->base + VNC8B_REG); | ||
1034 | iowrite32(p_set->coeff_set[23], priv->base + VNC8C_REG); | ||
1035 | } | ||
1036 | |||
1037 | /* rect is guaranteed to not exceed the scaled camera rectangle */ | ||
1038 | static int rcar_vin_set_rect(struct soc_camera_device *icd) | ||
1039 | { | ||
1040 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1041 | struct rcar_vin_cam *cam = icd->host_priv; | ||
1042 | struct rcar_vin_priv *priv = ici->priv; | ||
1043 | unsigned int left_offset, top_offset; | ||
1044 | unsigned char dsize = 0; | ||
1045 | struct v4l2_rect *cam_subrect = &cam->subrect; | ||
1046 | u32 value; | ||
1047 | |||
1048 | dev_dbg(icd->parent, "Crop %ux%u@%u:%u\n", | ||
1049 | icd->user_width, icd->user_height, cam->vin_left, cam->vin_top); | ||
1050 | |||
1051 | left_offset = cam->vin_left; | ||
1052 | top_offset = cam->vin_top; | ||
1053 | |||
1054 | if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_RGB32 && | ||
1055 | priv->chip == RCAR_E1) | ||
1056 | dsize = 1; | ||
1057 | |||
1058 | dev_dbg(icd->parent, "Cam %ux%u@%u:%u\n", | ||
1059 | cam->width, cam->height, cam->vin_left, cam->vin_top); | ||
1060 | dev_dbg(icd->parent, "Cam subrect %ux%u@%u:%u\n", | ||
1061 | cam_subrect->width, cam_subrect->height, | ||
1062 | cam_subrect->left, cam_subrect->top); | ||
1063 | |||
1064 | /* Set Start/End Pixel/Line Pre-Clip */ | ||
1065 | iowrite32(left_offset << dsize, priv->base + VNSPPRC_REG); | ||
1066 | iowrite32((left_offset + cam_subrect->width - 1) << dsize, | ||
1067 | priv->base + VNEPPRC_REG); | ||
1068 | switch (priv->field) { | ||
1069 | case V4L2_FIELD_INTERLACED: | ||
1070 | case V4L2_FIELD_INTERLACED_TB: | ||
1071 | case V4L2_FIELD_INTERLACED_BT: | ||
1072 | iowrite32(top_offset / 2, priv->base + VNSLPRC_REG); | ||
1073 | iowrite32((top_offset + cam_subrect->height) / 2 - 1, | ||
1074 | priv->base + VNELPRC_REG); | ||
1075 | break; | ||
1076 | default: | ||
1077 | iowrite32(top_offset, priv->base + VNSLPRC_REG); | ||
1078 | iowrite32(top_offset + cam_subrect->height - 1, | ||
1079 | priv->base + VNELPRC_REG); | ||
1080 | break; | ||
1081 | } | ||
1082 | |||
1083 | /* Set scaling coefficient */ | ||
1084 | value = 0; | ||
1085 | if (cam_subrect->height != cam->out_height) | ||
1086 | value = (4096 * cam_subrect->height) / cam->out_height; | ||
1087 | dev_dbg(icd->parent, "YS Value: %x\n", value); | ||
1088 | iowrite32(value, priv->base + VNYS_REG); | ||
1089 | |||
1090 | value = 0; | ||
1091 | if (cam_subrect->width != cam->out_width) | ||
1092 | value = (4096 * cam_subrect->width) / cam->out_width; | ||
1093 | |||
1094 | /* Horizontal upscaling is up to double size */ | ||
1095 | if (0 < value && value < 2048) | ||
1096 | value = 2048; | ||
1097 | |||
1098 | dev_dbg(icd->parent, "XS Value: %x\n", value); | ||
1099 | iowrite32(value, priv->base + VNXS_REG); | ||
1100 | |||
1101 | /* Horizontal upscaling is carried out by scaling down from double size */ | ||
1102 | if (value < 4096) | ||
1103 | value *= 2; | ||
1104 | |||
1105 | set_coeff(priv, value); | ||
1106 | |||
1107 | /* Set Start/End Pixel/Line Post-Clip */ | ||
1108 | iowrite32(0, priv->base + VNSPPOC_REG); | ||
1109 | iowrite32(0, priv->base + VNSLPOC_REG); | ||
1110 | iowrite32((cam->out_width - 1) << dsize, priv->base + VNEPPOC_REG); | ||
1111 | switch (priv->field) { | ||
1112 | case V4L2_FIELD_INTERLACED: | ||
1113 | case V4L2_FIELD_INTERLACED_TB: | ||
1114 | case V4L2_FIELD_INTERLACED_BT: | ||
1115 | iowrite32(cam->out_height / 2 - 1, | ||
1116 | priv->base + VNELPOC_REG); | ||
1117 | break; | ||
1118 | default: | ||
1119 | iowrite32(cam->out_height - 1, priv->base + VNELPOC_REG); | ||
1120 | break; | ||
1121 | } | ||
1122 | |||
1123 | iowrite32(ALIGN(cam->out_width, 0x10), priv->base + VNIS_REG); | ||
1124 | |||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | static void capture_stop_preserve(struct rcar_vin_priv *priv, u32 *vnmc) | ||
1129 | { | ||
1130 | *vnmc = ioread32(priv->base + VNMC_REG); | ||
1131 | /* module disable */ | ||
1132 | iowrite32(*vnmc & ~VNMC_ME, priv->base + VNMC_REG); | ||
1133 | } | ||
1134 | |||
1135 | static void capture_restore(struct rcar_vin_priv *priv, u32 vnmc) | ||
1136 | { | ||
1137 | unsigned long timeout = jiffies + 10 * HZ; | ||
1138 | |||
1139 | /* | ||
1140 | * Wait until the end of the current frame. It can take a long time, | ||
1141 | * but if it has been aborted by a MRST1 reset, it should exit sooner. | ||
1142 | */ | ||
1143 | while ((ioread32(priv->base + VNMS_REG) & VNMS_AV) && | ||
1144 | time_before(jiffies, timeout)) | ||
1145 | msleep(1); | ||
1146 | |||
1147 | if (time_after(jiffies, timeout)) { | ||
1148 | dev_err(priv->ici.v4l2_dev.dev, | ||
1149 | "Timeout waiting for frame end! Interface problem?\n"); | ||
1150 | return; | ||
1151 | } | ||
1152 | |||
1153 | iowrite32(vnmc, priv->base + VNMC_REG); | ||
1154 | } | ||
1155 | |||
1156 | #define VIN_MBUS_FLAGS (V4L2_MBUS_MASTER | \ | ||
1157 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ | ||
1158 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ | ||
1159 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ | ||
1160 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ | ||
1161 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ | ||
1162 | V4L2_MBUS_DATA_ACTIVE_HIGH) | ||
1163 | |||
1164 | static int rcar_vin_set_bus_param(struct soc_camera_device *icd) | ||
1165 | { | ||
1166 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1167 | struct rcar_vin_priv *priv = ici->priv; | ||
1168 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1169 | struct v4l2_mbus_config cfg; | ||
1170 | unsigned long common_flags; | ||
1171 | u32 vnmc; | ||
1172 | u32 val; | ||
1173 | int ret; | ||
1174 | |||
1175 | capture_stop_preserve(priv, &vnmc); | ||
1176 | |||
1177 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
1178 | if (!ret) { | ||
1179 | common_flags = soc_mbus_config_compatible(&cfg, VIN_MBUS_FLAGS); | ||
1180 | if (!common_flags) { | ||
1181 | dev_warn(icd->parent, | ||
1182 | "MBUS flags incompatible: camera 0x%x, host 0x%x\n", | ||
1183 | cfg.flags, VIN_MBUS_FLAGS); | ||
1184 | return -EINVAL; | ||
1185 | } | ||
1186 | } else if (ret != -ENOIOCTLCMD) { | ||
1187 | return ret; | ||
1188 | } else { | ||
1189 | common_flags = VIN_MBUS_FLAGS; | ||
1190 | } | ||
1191 | |||
1192 | /* Make choises, based on platform preferences */ | ||
1193 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && | ||
1194 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { | ||
1195 | if (priv->pdata_flags & RCAR_VIN_HSYNC_ACTIVE_LOW) | ||
1196 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; | ||
1197 | else | ||
1198 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; | ||
1199 | } | ||
1200 | |||
1201 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && | ||
1202 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { | ||
1203 | if (priv->pdata_flags & RCAR_VIN_VSYNC_ACTIVE_LOW) | ||
1204 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; | ||
1205 | else | ||
1206 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; | ||
1207 | } | ||
1208 | |||
1209 | cfg.flags = common_flags; | ||
1210 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | ||
1211 | if (ret < 0 && ret != -ENOIOCTLCMD) | ||
1212 | return ret; | ||
1213 | |||
1214 | val = VNDMR2_FTEV | VNDMR2_VLV(1); | ||
1215 | if (!(common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) | ||
1216 | val |= VNDMR2_VPS; | ||
1217 | if (!(common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) | ||
1218 | val |= VNDMR2_HPS; | ||
1219 | iowrite32(val, priv->base + VNDMR2_REG); | ||
1220 | |||
1221 | ret = rcar_vin_set_rect(icd); | ||
1222 | if (ret < 0) | ||
1223 | return ret; | ||
1224 | |||
1225 | capture_restore(priv, vnmc); | ||
1226 | |||
1227 | return 0; | ||
1228 | } | ||
1229 | |||
1230 | static int rcar_vin_try_bus_param(struct soc_camera_device *icd, | ||
1231 | unsigned char buswidth) | ||
1232 | { | ||
1233 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1234 | struct v4l2_mbus_config cfg; | ||
1235 | int ret; | ||
1236 | |||
1237 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
1238 | if (ret == -ENOIOCTLCMD) | ||
1239 | return 0; | ||
1240 | else if (ret) | ||
1241 | return ret; | ||
1242 | |||
1243 | if (buswidth > 24) | ||
1244 | return -EINVAL; | ||
1245 | |||
1246 | /* check is there common mbus flags */ | ||
1247 | ret = soc_mbus_config_compatible(&cfg, VIN_MBUS_FLAGS); | ||
1248 | if (ret) | ||
1249 | return 0; | ||
1250 | |||
1251 | dev_warn(icd->parent, | ||
1252 | "MBUS flags incompatible: camera 0x%x, host 0x%x\n", | ||
1253 | cfg.flags, VIN_MBUS_FLAGS); | ||
1254 | |||
1255 | return -EINVAL; | ||
1256 | } | ||
1257 | |||
1258 | static bool rcar_vin_packing_supported(const struct soc_mbus_pixelfmt *fmt) | ||
1259 | { | ||
1260 | return fmt->packing == SOC_MBUS_PACKING_NONE || | ||
1261 | (fmt->bits_per_sample > 8 && | ||
1262 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | ||
1263 | } | ||
1264 | |||
1265 | static const struct soc_mbus_pixelfmt rcar_vin_formats[] = { | ||
1266 | { | ||
1267 | .fourcc = V4L2_PIX_FMT_NV16, | ||
1268 | .name = "NV16", | ||
1269 | .bits_per_sample = 8, | ||
1270 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1271 | .order = SOC_MBUS_ORDER_LE, | ||
1272 | .layout = SOC_MBUS_LAYOUT_PLANAR_Y_C, | ||
1273 | }, | ||
1274 | { | ||
1275 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
1276 | .name = "YUYV", | ||
1277 | .bits_per_sample = 16, | ||
1278 | .packing = SOC_MBUS_PACKING_NONE, | ||
1279 | .order = SOC_MBUS_ORDER_LE, | ||
1280 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1281 | }, | ||
1282 | { | ||
1283 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
1284 | .name = "UYVY", | ||
1285 | .bits_per_sample = 16, | ||
1286 | .packing = SOC_MBUS_PACKING_NONE, | ||
1287 | .order = SOC_MBUS_ORDER_LE, | ||
1288 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1289 | }, | ||
1290 | { | ||
1291 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
1292 | .name = "RGB565", | ||
1293 | .bits_per_sample = 16, | ||
1294 | .packing = SOC_MBUS_PACKING_NONE, | ||
1295 | .order = SOC_MBUS_ORDER_LE, | ||
1296 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1297 | }, | ||
1298 | { | ||
1299 | .fourcc = V4L2_PIX_FMT_RGB555X, | ||
1300 | .name = "ARGB1555", | ||
1301 | .bits_per_sample = 16, | ||
1302 | .packing = SOC_MBUS_PACKING_NONE, | ||
1303 | .order = SOC_MBUS_ORDER_LE, | ||
1304 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1305 | }, | ||
1306 | { | ||
1307 | .fourcc = V4L2_PIX_FMT_RGB32, | ||
1308 | .name = "RGB888", | ||
1309 | .bits_per_sample = 32, | ||
1310 | .packing = SOC_MBUS_PACKING_NONE, | ||
1311 | .order = SOC_MBUS_ORDER_LE, | ||
1312 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1313 | }, | ||
1314 | { | ||
1315 | .fourcc = V4L2_PIX_FMT_ARGB32, | ||
1316 | .name = "ARGB8888", | ||
1317 | .bits_per_sample = 32, | ||
1318 | .packing = SOC_MBUS_PACKING_NONE, | ||
1319 | .order = SOC_MBUS_ORDER_LE, | ||
1320 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1321 | }, | ||
1322 | }; | ||
1323 | |||
1324 | static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, | ||
1325 | struct soc_camera_format_xlate *xlate) | ||
1326 | { | ||
1327 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1328 | struct device *dev = icd->parent; | ||
1329 | int ret, k, n; | ||
1330 | int formats = 0; | ||
1331 | struct rcar_vin_cam *cam; | ||
1332 | struct v4l2_subdev_mbus_code_enum code = { | ||
1333 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1334 | .index = idx, | ||
1335 | }; | ||
1336 | const struct soc_mbus_pixelfmt *fmt; | ||
1337 | |||
1338 | ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); | ||
1339 | if (ret < 0) | ||
1340 | return 0; | ||
1341 | |||
1342 | fmt = soc_mbus_get_fmtdesc(code.code); | ||
1343 | if (!fmt) { | ||
1344 | dev_warn(dev, "unsupported format code #%u: %d\n", idx, code.code); | ||
1345 | return 0; | ||
1346 | } | ||
1347 | |||
1348 | ret = rcar_vin_try_bus_param(icd, fmt->bits_per_sample); | ||
1349 | if (ret < 0) | ||
1350 | return 0; | ||
1351 | |||
1352 | if (!icd->host_priv) { | ||
1353 | struct v4l2_subdev_format fmt = { | ||
1354 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1355 | }; | ||
1356 | struct v4l2_mbus_framefmt *mf = &fmt.format; | ||
1357 | struct v4l2_rect rect; | ||
1358 | struct device *dev = icd->parent; | ||
1359 | int shift; | ||
1360 | |||
1361 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | ||
1362 | if (ret < 0) | ||
1363 | return ret; | ||
1364 | |||
1365 | /* Cache current client geometry */ | ||
1366 | ret = soc_camera_client_g_rect(sd, &rect); | ||
1367 | if (ret == -ENOIOCTLCMD) { | ||
1368 | /* Sensor driver doesn't support cropping */ | ||
1369 | rect.left = 0; | ||
1370 | rect.top = 0; | ||
1371 | rect.width = mf->width; | ||
1372 | rect.height = mf->height; | ||
1373 | } else if (ret < 0) { | ||
1374 | return ret; | ||
1375 | } | ||
1376 | |||
1377 | /* | ||
1378 | * If sensor proposes too large format then try smaller ones: | ||
1379 | * 1280x960, 640x480, 320x240 | ||
1380 | */ | ||
1381 | for (shift = 0; shift < 3; shift++) { | ||
1382 | if (mf->width <= VIN_MAX_WIDTH && | ||
1383 | mf->height <= VIN_MAX_HEIGHT) | ||
1384 | break; | ||
1385 | |||
1386 | mf->width = 1280 >> shift; | ||
1387 | mf->height = 960 >> shift; | ||
1388 | ret = v4l2_device_call_until_err(sd->v4l2_dev, | ||
1389 | soc_camera_grp_id(icd), | ||
1390 | pad, set_fmt, NULL, | ||
1391 | &fmt); | ||
1392 | if (ret < 0) | ||
1393 | return ret; | ||
1394 | } | ||
1395 | |||
1396 | if (shift == 3) { | ||
1397 | dev_err(dev, | ||
1398 | "Failed to configure the client below %ux%u\n", | ||
1399 | mf->width, mf->height); | ||
1400 | return -EIO; | ||
1401 | } | ||
1402 | |||
1403 | dev_dbg(dev, "camera fmt %ux%u\n", mf->width, mf->height); | ||
1404 | |||
1405 | cam = kzalloc(sizeof(*cam), GFP_KERNEL); | ||
1406 | if (!cam) | ||
1407 | return -ENOMEM; | ||
1408 | /* | ||
1409 | * We are called with current camera crop, | ||
1410 | * initialise subrect with it | ||
1411 | */ | ||
1412 | cam->rect = rect; | ||
1413 | cam->subrect = rect; | ||
1414 | cam->width = mf->width; | ||
1415 | cam->height = mf->height; | ||
1416 | cam->out_width = mf->width; | ||
1417 | cam->out_height = mf->height; | ||
1418 | |||
1419 | icd->host_priv = cam; | ||
1420 | } else { | ||
1421 | cam = icd->host_priv; | ||
1422 | } | ||
1423 | |||
1424 | /* Beginning of a pass */ | ||
1425 | if (!idx) | ||
1426 | cam->extra_fmt = NULL; | ||
1427 | |||
1428 | switch (code.code) { | ||
1429 | case MEDIA_BUS_FMT_YUYV8_1X16: | ||
1430 | case MEDIA_BUS_FMT_YUYV8_2X8: | ||
1431 | case MEDIA_BUS_FMT_YUYV10_2X10: | ||
1432 | case MEDIA_BUS_FMT_RGB888_1X24: | ||
1433 | if (cam->extra_fmt) | ||
1434 | break; | ||
1435 | |||
1436 | /* Add all our formats that can be generated by VIN */ | ||
1437 | cam->extra_fmt = rcar_vin_formats; | ||
1438 | |||
1439 | n = ARRAY_SIZE(rcar_vin_formats); | ||
1440 | formats += n; | ||
1441 | for (k = 0; xlate && k < n; k++, xlate++) { | ||
1442 | xlate->host_fmt = &rcar_vin_formats[k]; | ||
1443 | xlate->code = code.code; | ||
1444 | dev_dbg(dev, "Providing format %s using code %d\n", | ||
1445 | rcar_vin_formats[k].name, code.code); | ||
1446 | } | ||
1447 | break; | ||
1448 | default: | ||
1449 | if (!rcar_vin_packing_supported(fmt)) | ||
1450 | return 0; | ||
1451 | |||
1452 | dev_dbg(dev, "Providing format %s in pass-through mode\n", | ||
1453 | fmt->name); | ||
1454 | break; | ||
1455 | } | ||
1456 | |||
1457 | /* Generic pass-through */ | ||
1458 | formats++; | ||
1459 | if (xlate) { | ||
1460 | xlate->host_fmt = fmt; | ||
1461 | xlate->code = code.code; | ||
1462 | xlate++; | ||
1463 | } | ||
1464 | |||
1465 | return formats; | ||
1466 | } | ||
1467 | |||
1468 | static void rcar_vin_put_formats(struct soc_camera_device *icd) | ||
1469 | { | ||
1470 | kfree(icd->host_priv); | ||
1471 | icd->host_priv = NULL; | ||
1472 | } | ||
1473 | |||
1474 | static int rcar_vin_set_crop(struct soc_camera_device *icd, | ||
1475 | const struct v4l2_crop *a) | ||
1476 | { | ||
1477 | struct v4l2_crop a_writable = *a; | ||
1478 | const struct v4l2_rect *rect = &a_writable.c; | ||
1479 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1480 | struct rcar_vin_priv *priv = ici->priv; | ||
1481 | struct v4l2_crop cam_crop; | ||
1482 | struct rcar_vin_cam *cam = icd->host_priv; | ||
1483 | struct v4l2_rect *cam_rect = &cam_crop.c; | ||
1484 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1485 | struct device *dev = icd->parent; | ||
1486 | struct v4l2_subdev_format fmt = { | ||
1487 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1488 | }; | ||
1489 | struct v4l2_mbus_framefmt *mf = &fmt.format; | ||
1490 | u32 vnmc; | ||
1491 | int ret, i; | ||
1492 | |||
1493 | dev_dbg(dev, "S_CROP(%ux%u@%u:%u)\n", rect->width, rect->height, | ||
1494 | rect->left, rect->top); | ||
1495 | |||
1496 | /* During camera cropping its output window can change too, stop VIN */ | ||
1497 | capture_stop_preserve(priv, &vnmc); | ||
1498 | dev_dbg(dev, "VNMC_REG 0x%x\n", vnmc); | ||
1499 | |||
1500 | /* Apply iterative camera S_CROP for new input window. */ | ||
1501 | ret = soc_camera_client_s_crop(sd, &a_writable, &cam_crop, | ||
1502 | &cam->rect, &cam->subrect); | ||
1503 | if (ret < 0) | ||
1504 | return ret; | ||
1505 | |||
1506 | dev_dbg(dev, "camera cropped to %ux%u@%u:%u\n", | ||
1507 | cam_rect->width, cam_rect->height, | ||
1508 | cam_rect->left, cam_rect->top); | ||
1509 | |||
1510 | /* On success cam_crop contains current camera crop */ | ||
1511 | |||
1512 | /* Retrieve camera output window */ | ||
1513 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | ||
1514 | if (ret < 0) | ||
1515 | return ret; | ||
1516 | |||
1517 | if (mf->width > VIN_MAX_WIDTH || mf->height > VIN_MAX_HEIGHT) | ||
1518 | return -EINVAL; | ||
1519 | |||
1520 | /* Cache camera output window */ | ||
1521 | cam->width = mf->width; | ||
1522 | cam->height = mf->height; | ||
1523 | |||
1524 | icd->user_width = cam->width; | ||
1525 | icd->user_height = cam->height; | ||
1526 | |||
1527 | cam->vin_left = rect->left & ~1; | ||
1528 | cam->vin_top = rect->top & ~1; | ||
1529 | |||
1530 | /* Use VIN cropping to crop to the new window. */ | ||
1531 | ret = rcar_vin_set_rect(icd); | ||
1532 | if (ret < 0) | ||
1533 | return ret; | ||
1534 | |||
1535 | cam->subrect = *rect; | ||
1536 | |||
1537 | dev_dbg(dev, "VIN cropped to %ux%u@%u:%u\n", | ||
1538 | icd->user_width, icd->user_height, | ||
1539 | cam->vin_left, cam->vin_top); | ||
1540 | |||
1541 | /* Restore capture */ | ||
1542 | for (i = 0; i < MAX_BUFFER_NUM; i++) { | ||
1543 | if (priv->queue_buf[i] && priv->state == STOPPED) { | ||
1544 | vnmc |= VNMC_ME; | ||
1545 | break; | ||
1546 | } | ||
1547 | } | ||
1548 | capture_restore(priv, vnmc); | ||
1549 | |||
1550 | /* Even if only camera cropping succeeded */ | ||
1551 | return ret; | ||
1552 | } | ||
1553 | |||
1554 | static int rcar_vin_get_crop(struct soc_camera_device *icd, | ||
1555 | struct v4l2_crop *a) | ||
1556 | { | ||
1557 | struct rcar_vin_cam *cam = icd->host_priv; | ||
1558 | |||
1559 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1560 | a->c = cam->subrect; | ||
1561 | |||
1562 | return 0; | ||
1563 | } | ||
1564 | |||
1565 | /* Similar to set_crop multistage iterative algorithm */ | ||
1566 | static int rcar_vin_set_fmt(struct soc_camera_device *icd, | ||
1567 | struct v4l2_format *f) | ||
1568 | { | ||
1569 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1570 | struct rcar_vin_priv *priv = ici->priv; | ||
1571 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1572 | struct rcar_vin_cam *cam = icd->host_priv; | ||
1573 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1574 | struct v4l2_mbus_framefmt mf; | ||
1575 | struct device *dev = icd->parent; | ||
1576 | __u32 pixfmt = pix->pixelformat; | ||
1577 | const struct soc_camera_format_xlate *xlate; | ||
1578 | unsigned int vin_sub_width = 0, vin_sub_height = 0; | ||
1579 | int ret; | ||
1580 | bool can_scale; | ||
1581 | enum v4l2_field field; | ||
1582 | v4l2_std_id std; | ||
1583 | |||
1584 | dev_dbg(dev, "S_FMT(pix=0x%x, %ux%u)\n", | ||
1585 | pixfmt, pix->width, pix->height); | ||
1586 | |||
1587 | switch (pix->field) { | ||
1588 | default: | ||
1589 | pix->field = V4L2_FIELD_NONE; | ||
1590 | /* fall-through */ | ||
1591 | case V4L2_FIELD_NONE: | ||
1592 | case V4L2_FIELD_TOP: | ||
1593 | case V4L2_FIELD_BOTTOM: | ||
1594 | case V4L2_FIELD_INTERLACED_TB: | ||
1595 | case V4L2_FIELD_INTERLACED_BT: | ||
1596 | field = pix->field; | ||
1597 | break; | ||
1598 | case V4L2_FIELD_INTERLACED: | ||
1599 | /* Query for standard if not explicitly mentioned _TB/_BT */ | ||
1600 | ret = v4l2_subdev_call(sd, video, querystd, &std); | ||
1601 | if (ret == -ENOIOCTLCMD) { | ||
1602 | field = V4L2_FIELD_NONE; | ||
1603 | } else if (ret < 0) { | ||
1604 | return ret; | ||
1605 | } else { | ||
1606 | field = std & V4L2_STD_625_50 ? | ||
1607 | V4L2_FIELD_INTERLACED_TB : | ||
1608 | V4L2_FIELD_INTERLACED_BT; | ||
1609 | } | ||
1610 | break; | ||
1611 | } | ||
1612 | |||
1613 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
1614 | if (!xlate) { | ||
1615 | dev_warn(dev, "Format %x not found\n", pixfmt); | ||
1616 | return -EINVAL; | ||
1617 | } | ||
1618 | /* Calculate client output geometry */ | ||
1619 | soc_camera_calc_client_output(icd, &cam->rect, &cam->subrect, pix, &mf, | ||
1620 | 12); | ||
1621 | mf.field = pix->field; | ||
1622 | mf.colorspace = pix->colorspace; | ||
1623 | mf.code = xlate->code; | ||
1624 | |||
1625 | switch (pixfmt) { | ||
1626 | case V4L2_PIX_FMT_RGB32: | ||
1627 | can_scale = priv->chip != RCAR_E1; | ||
1628 | break; | ||
1629 | case V4L2_PIX_FMT_ARGB32: | ||
1630 | case V4L2_PIX_FMT_UYVY: | ||
1631 | case V4L2_PIX_FMT_YUYV: | ||
1632 | case V4L2_PIX_FMT_RGB565: | ||
1633 | case V4L2_PIX_FMT_RGB555X: | ||
1634 | can_scale = true; | ||
1635 | break; | ||
1636 | default: | ||
1637 | can_scale = false; | ||
1638 | break; | ||
1639 | } | ||
1640 | |||
1641 | dev_dbg(dev, "request camera output %ux%u\n", mf.width, mf.height); | ||
1642 | |||
1643 | ret = soc_camera_client_scale(icd, &cam->rect, &cam->subrect, | ||
1644 | &mf, &vin_sub_width, &vin_sub_height, | ||
1645 | can_scale, 12); | ||
1646 | |||
1647 | /* Done with the camera. Now see if we can improve the result */ | ||
1648 | dev_dbg(dev, "Camera %d fmt %ux%u, requested %ux%u\n", | ||
1649 | ret, mf.width, mf.height, pix->width, pix->height); | ||
1650 | |||
1651 | if (ret == -ENOIOCTLCMD) | ||
1652 | dev_dbg(dev, "Sensor doesn't support scaling\n"); | ||
1653 | else if (ret < 0) | ||
1654 | return ret; | ||
1655 | |||
1656 | if (mf.code != xlate->code) | ||
1657 | return -EINVAL; | ||
1658 | |||
1659 | /* Prepare VIN crop */ | ||
1660 | cam->width = mf.width; | ||
1661 | cam->height = mf.height; | ||
1662 | |||
1663 | /* Use VIN scaling to scale to the requested user window. */ | ||
1664 | |||
1665 | /* We cannot scale up */ | ||
1666 | if (pix->width > vin_sub_width) | ||
1667 | vin_sub_width = pix->width; | ||
1668 | |||
1669 | if (pix->height > vin_sub_height) | ||
1670 | vin_sub_height = pix->height; | ||
1671 | |||
1672 | pix->colorspace = mf.colorspace; | ||
1673 | |||
1674 | if (!can_scale) { | ||
1675 | pix->width = vin_sub_width; | ||
1676 | pix->height = vin_sub_height; | ||
1677 | } | ||
1678 | |||
1679 | /* | ||
1680 | * We have calculated CFLCR, the actual configuration will be performed | ||
1681 | * in rcar_vin_set_bus_param() | ||
1682 | */ | ||
1683 | |||
1684 | dev_dbg(dev, "W: %u : %u, H: %u : %u\n", | ||
1685 | vin_sub_width, pix->width, vin_sub_height, pix->height); | ||
1686 | |||
1687 | cam->out_width = pix->width; | ||
1688 | cam->out_height = pix->height; | ||
1689 | |||
1690 | icd->current_fmt = xlate; | ||
1691 | |||
1692 | priv->field = field; | ||
1693 | |||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1697 | static int rcar_vin_try_fmt(struct soc_camera_device *icd, | ||
1698 | struct v4l2_format *f) | ||
1699 | { | ||
1700 | const struct soc_camera_format_xlate *xlate; | ||
1701 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1702 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1703 | struct v4l2_subdev_pad_config pad_cfg; | ||
1704 | struct v4l2_subdev_format format = { | ||
1705 | .which = V4L2_SUBDEV_FORMAT_TRY, | ||
1706 | }; | ||
1707 | struct v4l2_mbus_framefmt *mf = &format.format; | ||
1708 | __u32 pixfmt = pix->pixelformat; | ||
1709 | int width, height; | ||
1710 | int ret; | ||
1711 | |||
1712 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
1713 | if (!xlate) { | ||
1714 | xlate = icd->current_fmt; | ||
1715 | dev_dbg(icd->parent, "Format %x not found, keeping %x\n", | ||
1716 | pixfmt, xlate->host_fmt->fourcc); | ||
1717 | pixfmt = xlate->host_fmt->fourcc; | ||
1718 | pix->pixelformat = pixfmt; | ||
1719 | pix->colorspace = icd->colorspace; | ||
1720 | } | ||
1721 | |||
1722 | /* FIXME: calculate using depth and bus width */ | ||
1723 | v4l_bound_align_image(&pix->width, 2, VIN_MAX_WIDTH, 1, | ||
1724 | &pix->height, 4, VIN_MAX_HEIGHT, 2, 0); | ||
1725 | |||
1726 | width = pix->width; | ||
1727 | height = pix->height; | ||
1728 | |||
1729 | /* let soc-camera calculate these values */ | ||
1730 | pix->bytesperline = 0; | ||
1731 | pix->sizeimage = 0; | ||
1732 | |||
1733 | /* limit to sensor capabilities */ | ||
1734 | mf->width = pix->width; | ||
1735 | mf->height = pix->height; | ||
1736 | mf->field = pix->field; | ||
1737 | mf->code = xlate->code; | ||
1738 | mf->colorspace = pix->colorspace; | ||
1739 | |||
1740 | ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), | ||
1741 | pad, set_fmt, &pad_cfg, &format); | ||
1742 | if (ret < 0) | ||
1743 | return ret; | ||
1744 | |||
1745 | /* Adjust only if VIN cannot scale */ | ||
1746 | if (pix->width > mf->width * 2) | ||
1747 | pix->width = mf->width * 2; | ||
1748 | if (pix->height > mf->height * 3) | ||
1749 | pix->height = mf->height * 3; | ||
1750 | |||
1751 | pix->field = mf->field; | ||
1752 | pix->colorspace = mf->colorspace; | ||
1753 | |||
1754 | if (pixfmt == V4L2_PIX_FMT_NV16) { | ||
1755 | /* FIXME: check against rect_max after converting soc-camera */ | ||
1756 | /* We can scale precisely, need a bigger image from camera */ | ||
1757 | if (pix->width < width || pix->height < height) { | ||
1758 | /* | ||
1759 | * We presume, the sensor behaves sanely, i.e. if | ||
1760 | * requested a bigger rectangle, it will not return a | ||
1761 | * smaller one. | ||
1762 | */ | ||
1763 | mf->width = VIN_MAX_WIDTH; | ||
1764 | mf->height = VIN_MAX_HEIGHT; | ||
1765 | ret = v4l2_device_call_until_err(sd->v4l2_dev, | ||
1766 | soc_camera_grp_id(icd), | ||
1767 | pad, set_fmt, &pad_cfg, | ||
1768 | &format); | ||
1769 | if (ret < 0) { | ||
1770 | dev_err(icd->parent, | ||
1771 | "client try_fmt() = %d\n", ret); | ||
1772 | return ret; | ||
1773 | } | ||
1774 | } | ||
1775 | /* We will scale exactly */ | ||
1776 | if (mf->width > width) | ||
1777 | pix->width = width; | ||
1778 | if (mf->height > height) | ||
1779 | pix->height = height; | ||
1780 | } | ||
1781 | |||
1782 | return ret; | ||
1783 | } | ||
1784 | |||
1785 | static unsigned int rcar_vin_poll(struct file *file, poll_table *pt) | ||
1786 | { | ||
1787 | struct soc_camera_device *icd = file->private_data; | ||
1788 | |||
1789 | return vb2_poll(&icd->vb2_vidq, file, pt); | ||
1790 | } | ||
1791 | |||
1792 | static int rcar_vin_querycap(struct soc_camera_host *ici, | ||
1793 | struct v4l2_capability *cap) | ||
1794 | { | ||
1795 | strlcpy(cap->card, "R_Car_VIN", sizeof(cap->card)); | ||
1796 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
1797 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
1798 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s%d", DRV_NAME, ici->nr); | ||
1799 | |||
1800 | return 0; | ||
1801 | } | ||
1802 | |||
1803 | static int rcar_vin_init_videobuf2(struct vb2_queue *vq, | ||
1804 | struct soc_camera_device *icd) | ||
1805 | { | ||
1806 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1807 | |||
1808 | vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1809 | vq->io_modes = VB2_MMAP | VB2_USERPTR; | ||
1810 | vq->drv_priv = icd; | ||
1811 | vq->ops = &rcar_vin_vb2_ops; | ||
1812 | vq->mem_ops = &vb2_dma_contig_memops; | ||
1813 | vq->buf_struct_size = sizeof(struct rcar_vin_buffer); | ||
1814 | vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
1815 | vq->lock = &ici->host_lock; | ||
1816 | vq->dev = ici->v4l2_dev.dev; | ||
1817 | |||
1818 | return vb2_queue_init(vq); | ||
1819 | } | ||
1820 | |||
1821 | static struct soc_camera_host_ops rcar_vin_host_ops = { | ||
1822 | .owner = THIS_MODULE, | ||
1823 | .add = rcar_vin_add_device, | ||
1824 | .remove = rcar_vin_remove_device, | ||
1825 | .get_formats = rcar_vin_get_formats, | ||
1826 | .put_formats = rcar_vin_put_formats, | ||
1827 | .get_crop = rcar_vin_get_crop, | ||
1828 | .set_crop = rcar_vin_set_crop, | ||
1829 | .try_fmt = rcar_vin_try_fmt, | ||
1830 | .set_fmt = rcar_vin_set_fmt, | ||
1831 | .poll = rcar_vin_poll, | ||
1832 | .querycap = rcar_vin_querycap, | ||
1833 | .set_bus_param = rcar_vin_set_bus_param, | ||
1834 | .init_videobuf2 = rcar_vin_init_videobuf2, | ||
1835 | }; | ||
1836 | |||
1837 | #ifdef CONFIG_OF | ||
1838 | static const struct of_device_id rcar_vin_of_table[] = { | ||
1839 | { .compatible = "renesas,vin-r8a7795", .data = (void *)RCAR_GEN3 }, | ||
1840 | { .compatible = "renesas,vin-r8a7794", .data = (void *)RCAR_GEN2 }, | ||
1841 | { .compatible = "renesas,vin-r8a7793", .data = (void *)RCAR_GEN2 }, | ||
1842 | { .compatible = "renesas,vin-r8a7791", .data = (void *)RCAR_GEN2 }, | ||
1843 | { .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 }, | ||
1844 | { .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 }, | ||
1845 | { .compatible = "renesas,vin-r8a7778", .data = (void *)RCAR_M1 }, | ||
1846 | { .compatible = "renesas,rcar-gen3-vin", .data = (void *)RCAR_GEN3 }, | ||
1847 | { .compatible = "renesas,rcar-gen2-vin", .data = (void *)RCAR_GEN2 }, | ||
1848 | { }, | ||
1849 | }; | ||
1850 | MODULE_DEVICE_TABLE(of, rcar_vin_of_table); | ||
1851 | #endif | ||
1852 | |||
1853 | static int rcar_vin_probe(struct platform_device *pdev) | ||
1854 | { | ||
1855 | const struct of_device_id *match = NULL; | ||
1856 | struct rcar_vin_priv *priv; | ||
1857 | struct v4l2_of_endpoint ep; | ||
1858 | struct device_node *np; | ||
1859 | struct resource *mem; | ||
1860 | unsigned int pdata_flags; | ||
1861 | int irq, ret; | ||
1862 | |||
1863 | match = of_match_device(of_match_ptr(rcar_vin_of_table), &pdev->dev); | ||
1864 | |||
1865 | np = of_graph_get_next_endpoint(pdev->dev.of_node, NULL); | ||
1866 | if (!np) { | ||
1867 | dev_err(&pdev->dev, "could not find endpoint\n"); | ||
1868 | return -EINVAL; | ||
1869 | } | ||
1870 | |||
1871 | ret = v4l2_of_parse_endpoint(np, &ep); | ||
1872 | if (ret) { | ||
1873 | dev_err(&pdev->dev, "could not parse endpoint\n"); | ||
1874 | return ret; | ||
1875 | } | ||
1876 | |||
1877 | if (ep.bus_type == V4L2_MBUS_BT656) | ||
1878 | pdata_flags = RCAR_VIN_BT656; | ||
1879 | else { | ||
1880 | pdata_flags = 0; | ||
1881 | if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
1882 | pdata_flags |= RCAR_VIN_HSYNC_ACTIVE_LOW; | ||
1883 | if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
1884 | pdata_flags |= RCAR_VIN_VSYNC_ACTIVE_LOW; | ||
1885 | } | ||
1886 | |||
1887 | of_node_put(np); | ||
1888 | |||
1889 | dev_dbg(&pdev->dev, "pdata_flags = %08x\n", pdata_flags); | ||
1890 | |||
1891 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1892 | if (mem == NULL) | ||
1893 | return -EINVAL; | ||
1894 | |||
1895 | irq = platform_get_irq(pdev, 0); | ||
1896 | if (irq <= 0) | ||
1897 | return -EINVAL; | ||
1898 | |||
1899 | priv = devm_kzalloc(&pdev->dev, sizeof(struct rcar_vin_priv), | ||
1900 | GFP_KERNEL); | ||
1901 | if (!priv) | ||
1902 | return -ENOMEM; | ||
1903 | |||
1904 | priv->base = devm_ioremap_resource(&pdev->dev, mem); | ||
1905 | if (IS_ERR(priv->base)) | ||
1906 | return PTR_ERR(priv->base); | ||
1907 | |||
1908 | ret = devm_request_irq(&pdev->dev, irq, rcar_vin_irq, IRQF_SHARED, | ||
1909 | dev_name(&pdev->dev), priv); | ||
1910 | if (ret) | ||
1911 | return ret; | ||
1912 | |||
1913 | priv->ici.priv = priv; | ||
1914 | priv->ici.v4l2_dev.dev = &pdev->dev; | ||
1915 | priv->ici.drv_name = dev_name(&pdev->dev); | ||
1916 | priv->ici.ops = &rcar_vin_host_ops; | ||
1917 | |||
1918 | priv->pdata_flags = pdata_flags; | ||
1919 | if (!match) { | ||
1920 | priv->ici.nr = pdev->id; | ||
1921 | priv->chip = pdev->id_entry->driver_data; | ||
1922 | } else { | ||
1923 | priv->ici.nr = of_alias_get_id(pdev->dev.of_node, "vin"); | ||
1924 | priv->chip = (enum chip_id)match->data; | ||
1925 | } | ||
1926 | |||
1927 | spin_lock_init(&priv->lock); | ||
1928 | INIT_LIST_HEAD(&priv->capture); | ||
1929 | |||
1930 | priv->state = STOPPED; | ||
1931 | |||
1932 | pm_suspend_ignore_children(&pdev->dev, true); | ||
1933 | pm_runtime_enable(&pdev->dev); | ||
1934 | |||
1935 | ret = soc_camera_host_register(&priv->ici); | ||
1936 | if (ret) | ||
1937 | goto cleanup; | ||
1938 | |||
1939 | return 0; | ||
1940 | |||
1941 | cleanup: | ||
1942 | pm_runtime_disable(&pdev->dev); | ||
1943 | |||
1944 | return ret; | ||
1945 | } | ||
1946 | |||
1947 | static int rcar_vin_remove(struct platform_device *pdev) | ||
1948 | { | ||
1949 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | ||
1950 | |||
1951 | soc_camera_host_unregister(soc_host); | ||
1952 | pm_runtime_disable(&pdev->dev); | ||
1953 | |||
1954 | return 0; | ||
1955 | } | ||
1956 | |||
1957 | static struct platform_driver rcar_vin_driver = { | ||
1958 | .probe = rcar_vin_probe, | ||
1959 | .remove = rcar_vin_remove, | ||
1960 | .driver = { | ||
1961 | .name = DRV_NAME, | ||
1962 | .of_match_table = of_match_ptr(rcar_vin_of_table), | ||
1963 | }, | ||
1964 | }; | ||
1965 | |||
1966 | module_platform_driver(rcar_vin_driver); | ||
1967 | |||
1968 | MODULE_LICENSE("GPL"); | ||
1969 | MODULE_ALIAS("platform:rcar_vin"); | ||
1970 | MODULE_DESCRIPTION("Renesas R-Car VIN camera host driver"); | ||
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 02b519dde42a..a15bfb5aea47 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c | |||
@@ -41,7 +41,6 @@ | |||
41 | #include <media/v4l2-dev.h> | 41 | #include <media/v4l2-dev.h> |
42 | #include <media/soc_camera.h> | 42 | #include <media/soc_camera.h> |
43 | #include <media/drv-intf/sh_mobile_ceu.h> | 43 | #include <media/drv-intf/sh_mobile_ceu.h> |
44 | #include <media/drv-intf/sh_mobile_csi2.h> | ||
45 | #include <media/videobuf2-dma-contig.h> | 44 | #include <media/videobuf2-dma-contig.h> |
46 | #include <media/v4l2-mediabus.h> | 45 | #include <media/v4l2-mediabus.h> |
47 | #include <media/drv-intf/soc_mediabus.h> | 46 | #include <media/drv-intf/soc_mediabus.h> |
@@ -99,11 +98,6 @@ struct sh_mobile_ceu_buffer { | |||
99 | 98 | ||
100 | struct sh_mobile_ceu_dev { | 99 | struct sh_mobile_ceu_dev { |
101 | struct soc_camera_host ici; | 100 | struct soc_camera_host ici; |
102 | /* Asynchronous CSI2 linking */ | ||
103 | struct v4l2_async_subdev *csi2_asd; | ||
104 | struct v4l2_subdev *csi2_sd; | ||
105 | /* Synchronous probing compatibility */ | ||
106 | struct platform_device *csi2_pdev; | ||
107 | 101 | ||
108 | unsigned int irq; | 102 | unsigned int irq; |
109 | void __iomem *base; | 103 | void __iomem *base; |
@@ -140,7 +134,7 @@ struct sh_mobile_ceu_cam { | |||
140 | unsigned int width; | 134 | unsigned int width; |
141 | unsigned int height; | 135 | unsigned int height; |
142 | /* | 136 | /* |
143 | * User window from S_CROP / G_CROP, produced by client cropping and | 137 | * User window from S_SELECTION / G_SELECTION, produced by client cropping and |
144 | * scaling, CEU scaling and CEU cropping, mapped back onto the client | 138 | * scaling, CEU scaling and CEU cropping, mapped back onto the client |
145 | * input window | 139 | * input window |
146 | */ | 140 | */ |
@@ -470,7 +464,7 @@ static void sh_mobile_ceu_stop_streaming(struct vb2_queue *q) | |||
470 | sh_mobile_ceu_soft_reset(pcdev); | 464 | sh_mobile_ceu_soft_reset(pcdev); |
471 | } | 465 | } |
472 | 466 | ||
473 | static struct vb2_ops sh_mobile_ceu_videobuf_ops = { | 467 | static const struct vb2_ops sh_mobile_ceu_videobuf_ops = { |
474 | .queue_setup = sh_mobile_ceu_videobuf_setup, | 468 | .queue_setup = sh_mobile_ceu_videobuf_setup, |
475 | .buf_prepare = sh_mobile_ceu_videobuf_prepare, | 469 | .buf_prepare = sh_mobile_ceu_videobuf_prepare, |
476 | .buf_queue = sh_mobile_ceu_videobuf_queue, | 470 | .buf_queue = sh_mobile_ceu_videobuf_queue, |
@@ -517,74 +511,20 @@ out: | |||
517 | return IRQ_HANDLED; | 511 | return IRQ_HANDLED; |
518 | } | 512 | } |
519 | 513 | ||
520 | static struct v4l2_subdev *find_csi2(struct sh_mobile_ceu_dev *pcdev) | ||
521 | { | ||
522 | struct v4l2_subdev *sd; | ||
523 | |||
524 | if (pcdev->csi2_sd) | ||
525 | return pcdev->csi2_sd; | ||
526 | |||
527 | if (pcdev->csi2_asd) { | ||
528 | char name[] = "sh-mobile-csi2"; | ||
529 | v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev) | ||
530 | if (!strncmp(name, sd->name, sizeof(name) - 1)) { | ||
531 | pcdev->csi2_sd = sd; | ||
532 | return sd; | ||
533 | } | ||
534 | } | ||
535 | |||
536 | return NULL; | ||
537 | } | ||
538 | |||
539 | static struct v4l2_subdev *csi2_subdev(struct sh_mobile_ceu_dev *pcdev, | ||
540 | struct soc_camera_device *icd) | ||
541 | { | ||
542 | struct v4l2_subdev *sd = pcdev->csi2_sd; | ||
543 | |||
544 | return sd && sd->grp_id == soc_camera_grp_id(icd) ? sd : NULL; | ||
545 | } | ||
546 | |||
547 | static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | 514 | static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) |
548 | { | 515 | { |
549 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
550 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
551 | struct v4l2_subdev *csi2_sd = find_csi2(pcdev); | ||
552 | int ret; | ||
553 | |||
554 | if (csi2_sd) { | ||
555 | csi2_sd->grp_id = soc_camera_grp_id(icd); | ||
556 | v4l2_set_subdev_hostdata(csi2_sd, icd); | ||
557 | } | ||
558 | |||
559 | ret = v4l2_subdev_call(csi2_sd, core, s_power, 1); | ||
560 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | ||
561 | return ret; | ||
562 | |||
563 | /* | ||
564 | * -ENODEV is special: either csi2_sd == NULL or the CSI-2 driver | ||
565 | * has not found this soc-camera device among its clients | ||
566 | */ | ||
567 | if (csi2_sd && ret == -ENODEV) | ||
568 | csi2_sd->grp_id = 0; | ||
569 | |||
570 | dev_info(icd->parent, | 516 | dev_info(icd->parent, |
571 | "SuperH Mobile CEU%s driver attached to camera %d\n", | 517 | "SuperH Mobile CEU driver attached to camera %d\n", |
572 | csi2_sd && csi2_sd->grp_id ? "/CSI-2" : "", icd->devnum); | 518 | icd->devnum); |
573 | 519 | ||
574 | return 0; | 520 | return 0; |
575 | } | 521 | } |
576 | 522 | ||
577 | static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) | 523 | static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) |
578 | { | 524 | { |
579 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
580 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
581 | struct v4l2_subdev *csi2_sd = find_csi2(pcdev); | ||
582 | |||
583 | dev_info(icd->parent, | 525 | dev_info(icd->parent, |
584 | "SuperH Mobile CEU driver detached from camera %d\n", | 526 | "SuperH Mobile CEU driver detached from camera %d\n", |
585 | icd->devnum); | 527 | icd->devnum); |
586 | |||
587 | v4l2_subdev_call(csi2_sd, core, s_power, 0); | ||
588 | } | 528 | } |
589 | 529 | ||
590 | /* Called with .host_lock held */ | 530 | /* Called with .host_lock held */ |
@@ -704,12 +644,6 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) | |||
704 | cdwdr_width *= 2; | 644 | cdwdr_width *= 2; |
705 | } | 645 | } |
706 | 646 | ||
707 | /* CSI2 special configuration */ | ||
708 | if (csi2_subdev(pcdev, icd)) { | ||
709 | in_width = ((in_width - 2) * 2); | ||
710 | left_offset *= 2; | ||
711 | } | ||
712 | |||
713 | /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */ | 647 | /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */ |
714 | camor = left_offset | (top_offset << 16); | 648 | camor = left_offset | (top_offset << 16); |
715 | 649 | ||
@@ -758,13 +692,6 @@ static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr) | |||
758 | ceu_write(pcdev, CAPSR, capsr); | 692 | ceu_write(pcdev, CAPSR, capsr); |
759 | } | 693 | } |
760 | 694 | ||
761 | /* Find the bus subdevice driver, e.g., CSI2 */ | ||
762 | static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev, | ||
763 | struct soc_camera_device *icd) | ||
764 | { | ||
765 | return csi2_subdev(pcdev, icd) ? : soc_camera_to_subdev(icd); | ||
766 | } | ||
767 | |||
768 | #define CEU_BUS_FLAGS (V4L2_MBUS_MASTER | \ | 695 | #define CEU_BUS_FLAGS (V4L2_MBUS_MASTER | \ |
769 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ | 696 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ |
770 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ | 697 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ |
@@ -778,7 +705,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd) | |||
778 | { | 705 | { |
779 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 706 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
780 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 707 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
781 | struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); | 708 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
782 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | 709 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
783 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | 710 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
784 | unsigned long value, common_flags = CEU_BUS_FLAGS; | 711 | unsigned long value, common_flags = CEU_BUS_FLAGS; |
@@ -866,9 +793,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd) | |||
866 | value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; | 793 | value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; |
867 | value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; | 794 | value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; |
868 | 795 | ||
869 | if (csi2_subdev(pcdev, icd)) /* CSI2 mode */ | 796 | if (pcdev->is_16bit) |
870 | value |= 3 << 12; | ||
871 | else if (pcdev->is_16bit) | ||
872 | value |= 1 << 12; | 797 | value |= 1 << 12; |
873 | else if (pcdev->flags & SH_CEU_FLAG_LOWER_8BIT) | 798 | else if (pcdev->flags & SH_CEU_FLAG_LOWER_8BIT) |
874 | value |= 2 << 12; | 799 | value |= 2 << 12; |
@@ -923,9 +848,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd) | |||
923 | static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, | 848 | static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, |
924 | unsigned char buswidth) | 849 | unsigned char buswidth) |
925 | { | 850 | { |
926 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 851 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
927 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
928 | struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); | ||
929 | unsigned long common_flags = CEU_BUS_FLAGS; | 852 | unsigned long common_flags = CEU_BUS_FLAGS; |
930 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | 853 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
931 | int ret; | 854 | int ret; |
@@ -1046,12 +969,9 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int | |||
1046 | return 0; | 969 | return 0; |
1047 | } | 970 | } |
1048 | 971 | ||
1049 | if (!csi2_subdev(pcdev, icd)) { | 972 | ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); |
1050 | /* Are there any restrictions in the CSI-2 case? */ | 973 | if (ret < 0) |
1051 | ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); | 974 | return 0; |
1052 | if (ret < 0) | ||
1053 | return 0; | ||
1054 | } | ||
1055 | 975 | ||
1056 | if (!icd->host_priv) { | 976 | if (!icd->host_priv) { |
1057 | struct v4l2_subdev_format fmt = { | 977 | struct v4l2_subdev_format fmt = { |
@@ -1189,17 +1109,16 @@ static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd) | |||
1189 | * Documentation/video4linux/sh_mobile_ceu_camera.txt for a description of | 1109 | * Documentation/video4linux/sh_mobile_ceu_camera.txt for a description of |
1190 | * scaling and cropping algorithms and for the meaning of referenced here steps. | 1110 | * scaling and cropping algorithms and for the meaning of referenced here steps. |
1191 | */ | 1111 | */ |
1192 | static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | 1112 | static int sh_mobile_ceu_set_selection(struct soc_camera_device *icd, |
1193 | const struct v4l2_crop *a) | 1113 | struct v4l2_selection *sel) |
1194 | { | 1114 | { |
1195 | struct v4l2_crop a_writable = *a; | 1115 | struct v4l2_rect *rect = &sel->r; |
1196 | const struct v4l2_rect *rect = &a_writable.c; | ||
1197 | struct device *dev = icd->parent; | 1116 | struct device *dev = icd->parent; |
1198 | struct soc_camera_host *ici = to_soc_camera_host(dev); | 1117 | struct soc_camera_host *ici = to_soc_camera_host(dev); |
1199 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 1118 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
1200 | struct v4l2_crop cam_crop; | 1119 | struct v4l2_selection cam_sel; |
1201 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | 1120 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
1202 | struct v4l2_rect *cam_rect = &cam_crop.c; | 1121 | struct v4l2_rect *cam_rect = &cam_sel.r; |
1203 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1122 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1204 | struct v4l2_subdev_format fmt = { | 1123 | struct v4l2_subdev_format fmt = { |
1205 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | 1124 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
@@ -1211,7 +1130,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
1211 | u32 capsr, cflcr; | 1130 | u32 capsr, cflcr; |
1212 | int ret; | 1131 | int ret; |
1213 | 1132 | ||
1214 | dev_geo(dev, "S_CROP(%ux%u@%u:%u)\n", rect->width, rect->height, | 1133 | dev_geo(dev, "S_SELECTION(%ux%u@%u:%u)\n", rect->width, rect->height, |
1215 | rect->left, rect->top); | 1134 | rect->left, rect->top); |
1216 | 1135 | ||
1217 | /* During camera cropping its output window can change too, stop CEU */ | 1136 | /* During camera cropping its output window can change too, stop CEU */ |
@@ -1219,10 +1138,10 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
1219 | dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); | 1138 | dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); |
1220 | 1139 | ||
1221 | /* | 1140 | /* |
1222 | * 1. - 2. Apply iterative camera S_CROP for new input window, read back | 1141 | * 1. - 2. Apply iterative camera S_SELECTION for new input window, read back |
1223 | * actual camera rectangle. | 1142 | * actual camera rectangle. |
1224 | */ | 1143 | */ |
1225 | ret = soc_camera_client_s_crop(sd, &a_writable, &cam_crop, | 1144 | ret = soc_camera_client_s_selection(sd, sel, &cam_sel, |
1226 | &cam->rect, &cam->subrect); | 1145 | &cam->rect, &cam->subrect); |
1227 | if (ret < 0) | 1146 | if (ret < 0) |
1228 | return ret; | 1147 | return ret; |
@@ -1331,13 +1250,12 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
1331 | return ret; | 1250 | return ret; |
1332 | } | 1251 | } |
1333 | 1252 | ||
1334 | static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd, | 1253 | static int sh_mobile_ceu_get_selection(struct soc_camera_device *icd, |
1335 | struct v4l2_crop *a) | 1254 | struct v4l2_selection *sel) |
1336 | { | 1255 | { |
1337 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | 1256 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
1338 | 1257 | ||
1339 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1258 | sel->r = cam->subrect; |
1340 | a->c = cam->subrect; | ||
1341 | 1259 | ||
1342 | return 0; | 1260 | return 0; |
1343 | } | 1261 | } |
@@ -1579,8 +1497,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
1579 | return ret; | 1497 | return ret; |
1580 | } | 1498 | } |
1581 | 1499 | ||
1582 | static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd, | 1500 | static int sh_mobile_ceu_set_liveselection(struct soc_camera_device *icd, |
1583 | const struct v4l2_crop *a) | 1501 | struct v4l2_selection *sel) |
1584 | { | 1502 | { |
1585 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1503 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1586 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 1504 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
@@ -1599,7 +1517,7 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd, | |||
1599 | "Client failed to stop the stream: %d\n", ret); | 1517 | "Client failed to stop the stream: %d\n", ret); |
1600 | else | 1518 | else |
1601 | /* Do the crop, if it fails, there's nothing more we can do */ | 1519 | /* Do the crop, if it fails, there's nothing more we can do */ |
1602 | sh_mobile_ceu_set_crop(icd, a); | 1520 | sh_mobile_ceu_set_selection(icd, sel); |
1603 | 1521 | ||
1604 | dev_geo(icd->parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height); | 1522 | dev_geo(icd->parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height); |
1605 | 1523 | ||
@@ -1680,9 +1598,9 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { | |||
1680 | .clock_stop = sh_mobile_ceu_clock_stop, | 1598 | .clock_stop = sh_mobile_ceu_clock_stop, |
1681 | .get_formats = sh_mobile_ceu_get_formats, | 1599 | .get_formats = sh_mobile_ceu_get_formats, |
1682 | .put_formats = sh_mobile_ceu_put_formats, | 1600 | .put_formats = sh_mobile_ceu_put_formats, |
1683 | .get_crop = sh_mobile_ceu_get_crop, | 1601 | .get_selection = sh_mobile_ceu_get_selection, |
1684 | .set_crop = sh_mobile_ceu_set_crop, | 1602 | .set_selection = sh_mobile_ceu_set_selection, |
1685 | .set_livecrop = sh_mobile_ceu_set_livecrop, | 1603 | .set_liveselection = sh_mobile_ceu_set_liveselection, |
1686 | .set_fmt = sh_mobile_ceu_set_fmt, | 1604 | .set_fmt = sh_mobile_ceu_set_fmt, |
1687 | .try_fmt = sh_mobile_ceu_try_fmt, | 1605 | .try_fmt = sh_mobile_ceu_try_fmt, |
1688 | .poll = sh_mobile_ceu_poll, | 1606 | .poll = sh_mobile_ceu_poll, |
@@ -1721,12 +1639,11 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) | |||
1721 | struct resource *res; | 1639 | struct resource *res; |
1722 | void __iomem *base; | 1640 | void __iomem *base; |
1723 | unsigned int irq; | 1641 | unsigned int irq; |
1724 | int err, i; | 1642 | int err; |
1725 | struct bus_wait wait = { | 1643 | struct bus_wait wait = { |
1726 | .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion), | 1644 | .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion), |
1727 | .notifier.notifier_call = bus_notify, | 1645 | .notifier.notifier_call = bus_notify, |
1728 | }; | 1646 | }; |
1729 | struct sh_mobile_ceu_companion *csi2; | ||
1730 | 1647 | ||
1731 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1648 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1732 | irq = platform_get_irq(pdev, 0); | 1649 | irq = platform_get_irq(pdev, 0); |
@@ -1821,132 +1738,16 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) | |||
1821 | pcdev->ici.capabilities = SOCAM_HOST_CAP_STRIDE; | 1738 | pcdev->ici.capabilities = SOCAM_HOST_CAP_STRIDE; |
1822 | 1739 | ||
1823 | if (pcdev->pdata && pcdev->pdata->asd_sizes) { | 1740 | if (pcdev->pdata && pcdev->pdata->asd_sizes) { |
1824 | struct v4l2_async_subdev **asd; | ||
1825 | char name[] = "sh-mobile-csi2"; | ||
1826 | int j; | ||
1827 | |||
1828 | /* | ||
1829 | * CSI2 interfacing: several groups can use CSI2, pick up the | ||
1830 | * first one | ||
1831 | */ | ||
1832 | asd = pcdev->pdata->asd; | ||
1833 | for (j = 0; pcdev->pdata->asd_sizes[j]; j++) { | ||
1834 | for (i = 0; i < pcdev->pdata->asd_sizes[j]; i++, asd++) { | ||
1835 | dev_dbg(&pdev->dev, "%s(): subdev #%d, type %u\n", | ||
1836 | __func__, i, (*asd)->match_type); | ||
1837 | if ((*asd)->match_type == V4L2_ASYNC_MATCH_DEVNAME && | ||
1838 | !strncmp(name, (*asd)->match.device_name.name, | ||
1839 | sizeof(name) - 1)) { | ||
1840 | pcdev->csi2_asd = *asd; | ||
1841 | break; | ||
1842 | } | ||
1843 | } | ||
1844 | if (pcdev->csi2_asd) | ||
1845 | break; | ||
1846 | } | ||
1847 | |||
1848 | pcdev->ici.asd = pcdev->pdata->asd; | 1741 | pcdev->ici.asd = pcdev->pdata->asd; |
1849 | pcdev->ici.asd_sizes = pcdev->pdata->asd_sizes; | 1742 | pcdev->ici.asd_sizes = pcdev->pdata->asd_sizes; |
1850 | } | 1743 | } |
1851 | 1744 | ||
1852 | /* Legacy CSI2 interfacing */ | ||
1853 | csi2 = pcdev->pdata ? pcdev->pdata->csi2 : NULL; | ||
1854 | if (csi2) { | ||
1855 | /* | ||
1856 | * TODO: remove this once all users are converted to | ||
1857 | * asynchronous CSI2 probing. If it has to be kept, csi2 | ||
1858 | * platform device resources have to be added, using | ||
1859 | * platform_device_add_resources() | ||
1860 | */ | ||
1861 | struct platform_device *csi2_pdev = | ||
1862 | platform_device_alloc("sh-mobile-csi2", csi2->id); | ||
1863 | struct sh_csi2_pdata *csi2_pdata = csi2->platform_data; | ||
1864 | |||
1865 | if (!csi2_pdev) { | ||
1866 | err = -ENOMEM; | ||
1867 | goto exit_free_clk; | ||
1868 | } | ||
1869 | |||
1870 | pcdev->csi2_pdev = csi2_pdev; | ||
1871 | |||
1872 | err = platform_device_add_data(csi2_pdev, csi2_pdata, | ||
1873 | sizeof(*csi2_pdata)); | ||
1874 | if (err < 0) | ||
1875 | goto exit_pdev_put; | ||
1876 | |||
1877 | csi2_pdev->resource = csi2->resource; | ||
1878 | csi2_pdev->num_resources = csi2->num_resources; | ||
1879 | |||
1880 | err = platform_device_add(csi2_pdev); | ||
1881 | if (err < 0) | ||
1882 | goto exit_pdev_put; | ||
1883 | |||
1884 | wait.dev = &csi2_pdev->dev; | ||
1885 | |||
1886 | err = bus_register_notifier(&platform_bus_type, &wait.notifier); | ||
1887 | if (err < 0) | ||
1888 | goto exit_pdev_unregister; | ||
1889 | |||
1890 | /* | ||
1891 | * From this point the driver module will not unload, until | ||
1892 | * we complete the completion. | ||
1893 | */ | ||
1894 | |||
1895 | if (!csi2_pdev->dev.driver) { | ||
1896 | complete(&wait.completion); | ||
1897 | /* Either too late, or probing failed */ | ||
1898 | bus_unregister_notifier(&platform_bus_type, &wait.notifier); | ||
1899 | err = -ENXIO; | ||
1900 | goto exit_pdev_unregister; | ||
1901 | } | ||
1902 | |||
1903 | /* | ||
1904 | * The module is still loaded, in the worst case it is hanging | ||
1905 | * in device release on our completion. So, _now_ dereferencing | ||
1906 | * the "owner" is safe! | ||
1907 | */ | ||
1908 | |||
1909 | err = try_module_get(csi2_pdev->dev.driver->owner); | ||
1910 | |||
1911 | /* Let notifier complete, if it has been locked */ | ||
1912 | complete(&wait.completion); | ||
1913 | bus_unregister_notifier(&platform_bus_type, &wait.notifier); | ||
1914 | if (!err) { | ||
1915 | err = -ENODEV; | ||
1916 | goto exit_pdev_unregister; | ||
1917 | } | ||
1918 | |||
1919 | pcdev->csi2_sd = platform_get_drvdata(csi2_pdev); | ||
1920 | } | ||
1921 | |||
1922 | err = soc_camera_host_register(&pcdev->ici); | 1745 | err = soc_camera_host_register(&pcdev->ici); |
1923 | if (err) | 1746 | if (err) |
1924 | goto exit_csi2_unregister; | 1747 | goto exit_free_clk; |
1925 | |||
1926 | if (csi2) { | ||
1927 | err = v4l2_device_register_subdev(&pcdev->ici.v4l2_dev, | ||
1928 | pcdev->csi2_sd); | ||
1929 | dev_dbg(&pdev->dev, "%s(): ret(register_subdev) = %d\n", | ||
1930 | __func__, err); | ||
1931 | if (err < 0) | ||
1932 | goto exit_host_unregister; | ||
1933 | /* v4l2_device_register_subdev() took a reference too */ | ||
1934 | module_put(pcdev->csi2_sd->owner); | ||
1935 | } | ||
1936 | 1748 | ||
1937 | return 0; | 1749 | return 0; |
1938 | 1750 | ||
1939 | exit_host_unregister: | ||
1940 | soc_camera_host_unregister(&pcdev->ici); | ||
1941 | exit_csi2_unregister: | ||
1942 | if (csi2) { | ||
1943 | module_put(pcdev->csi2_pdev->dev.driver->owner); | ||
1944 | exit_pdev_unregister: | ||
1945 | platform_device_del(pcdev->csi2_pdev); | ||
1946 | exit_pdev_put: | ||
1947 | pcdev->csi2_pdev->resource = NULL; | ||
1948 | platform_device_put(pcdev->csi2_pdev); | ||
1949 | } | ||
1950 | exit_free_clk: | 1751 | exit_free_clk: |
1951 | pm_runtime_disable(&pdev->dev); | 1752 | pm_runtime_disable(&pdev->dev); |
1952 | exit_release_mem: | 1753 | exit_release_mem: |
@@ -1958,21 +1759,11 @@ exit_release_mem: | |||
1958 | static int sh_mobile_ceu_remove(struct platform_device *pdev) | 1759 | static int sh_mobile_ceu_remove(struct platform_device *pdev) |
1959 | { | 1760 | { |
1960 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | 1761 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); |
1961 | struct sh_mobile_ceu_dev *pcdev = container_of(soc_host, | ||
1962 | struct sh_mobile_ceu_dev, ici); | ||
1963 | struct platform_device *csi2_pdev = pcdev->csi2_pdev; | ||
1964 | 1762 | ||
1965 | soc_camera_host_unregister(soc_host); | 1763 | soc_camera_host_unregister(soc_host); |
1966 | pm_runtime_disable(&pdev->dev); | 1764 | pm_runtime_disable(&pdev->dev); |
1967 | if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) | 1765 | if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) |
1968 | dma_release_declared_memory(&pdev->dev); | 1766 | dma_release_declared_memory(&pdev->dev); |
1969 | if (csi2_pdev && csi2_pdev->dev.driver) { | ||
1970 | struct module *csi2_drv = csi2_pdev->dev.driver->owner; | ||
1971 | platform_device_del(csi2_pdev); | ||
1972 | csi2_pdev->resource = NULL; | ||
1973 | platform_device_put(csi2_pdev); | ||
1974 | module_put(csi2_drv); | ||
1975 | } | ||
1976 | 1767 | ||
1977 | return 0; | 1768 | return 0; |
1978 | } | 1769 | } |
@@ -2012,8 +1803,6 @@ static struct platform_driver sh_mobile_ceu_driver = { | |||
2012 | 1803 | ||
2013 | static int __init sh_mobile_ceu_init(void) | 1804 | static int __init sh_mobile_ceu_init(void) |
2014 | { | 1805 | { |
2015 | /* Whatever return code */ | ||
2016 | request_module("sh_mobile_csi2"); | ||
2017 | return platform_driver_register(&sh_mobile_ceu_driver); | 1806 | return platform_driver_register(&sh_mobile_ceu_driver); |
2018 | } | 1807 | } |
2019 | 1808 | ||
diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c deleted file mode 100644 index 09b18365a4b1..000000000000 --- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c +++ /dev/null | |||
@@ -1,400 +0,0 @@ | |||
1 | /* | ||
2 | * Driver for the SH-Mobile MIPI CSI-2 unit | ||
3 | * | ||
4 | * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/delay.h> | ||
12 | #include <linux/err.h> | ||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/pm_runtime.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/videodev2.h> | ||
19 | #include <linux/module.h> | ||
20 | |||
21 | #include <media/drv-intf/sh_mobile_ceu.h> | ||
22 | #include <media/drv-intf/sh_mobile_csi2.h> | ||
23 | #include <media/soc_camera.h> | ||
24 | #include <media/drv-intf/soc_mediabus.h> | ||
25 | #include <media/v4l2-common.h> | ||
26 | #include <media/v4l2-dev.h> | ||
27 | #include <media/v4l2-device.h> | ||
28 | #include <media/v4l2-mediabus.h> | ||
29 | #include <media/v4l2-subdev.h> | ||
30 | |||
31 | #define SH_CSI2_TREF 0x00 | ||
32 | #define SH_CSI2_SRST 0x04 | ||
33 | #define SH_CSI2_PHYCNT 0x08 | ||
34 | #define SH_CSI2_CHKSUM 0x0C | ||
35 | #define SH_CSI2_VCDT 0x10 | ||
36 | |||
37 | struct sh_csi2 { | ||
38 | struct v4l2_subdev subdev; | ||
39 | unsigned int irq; | ||
40 | unsigned long mipi_flags; | ||
41 | void __iomem *base; | ||
42 | struct platform_device *pdev; | ||
43 | struct sh_csi2_client_config *client; | ||
44 | }; | ||
45 | |||
46 | static void sh_csi2_hwinit(struct sh_csi2 *priv); | ||
47 | |||
48 | static int sh_csi2_set_fmt(struct v4l2_subdev *sd, | ||
49 | struct v4l2_subdev_pad_config *cfg, | ||
50 | struct v4l2_subdev_format *format) | ||
51 | { | ||
52 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
53 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | ||
54 | struct v4l2_mbus_framefmt *mf = &format->format; | ||
55 | u32 tmp = (priv->client->channel & 3) << 8; | ||
56 | |||
57 | if (format->pad) | ||
58 | return -EINVAL; | ||
59 | |||
60 | if (mf->width > 8188) | ||
61 | mf->width = 8188; | ||
62 | else if (mf->width & 1) | ||
63 | mf->width &= ~1; | ||
64 | |||
65 | switch (pdata->type) { | ||
66 | case SH_CSI2C: | ||
67 | switch (mf->code) { | ||
68 | case MEDIA_BUS_FMT_UYVY8_2X8: /* YUV422 */ | ||
69 | case MEDIA_BUS_FMT_YUYV8_1_5X8: /* YUV420 */ | ||
70 | case MEDIA_BUS_FMT_Y8_1X8: /* RAW8 */ | ||
71 | case MEDIA_BUS_FMT_SBGGR8_1X8: | ||
72 | case MEDIA_BUS_FMT_SGRBG8_1X8: | ||
73 | break; | ||
74 | default: | ||
75 | /* All MIPI CSI-2 devices must support one of primary formats */ | ||
76 | mf->code = MEDIA_BUS_FMT_YUYV8_2X8; | ||
77 | } | ||
78 | break; | ||
79 | case SH_CSI2I: | ||
80 | switch (mf->code) { | ||
81 | case MEDIA_BUS_FMT_Y8_1X8: /* RAW8 */ | ||
82 | case MEDIA_BUS_FMT_SBGGR8_1X8: | ||
83 | case MEDIA_BUS_FMT_SGRBG8_1X8: | ||
84 | case MEDIA_BUS_FMT_SBGGR10_1X10: /* RAW10 */ | ||
85 | case MEDIA_BUS_FMT_SBGGR12_1X12: /* RAW12 */ | ||
86 | break; | ||
87 | default: | ||
88 | /* All MIPI CSI-2 devices must support one of primary formats */ | ||
89 | mf->code = MEDIA_BUS_FMT_SBGGR8_1X8; | ||
90 | } | ||
91 | break; | ||
92 | } | ||
93 | |||
94 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
95 | cfg->try_fmt = *mf; | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | if (mf->width > 8188 || mf->width & 1) | ||
100 | return -EINVAL; | ||
101 | |||
102 | switch (mf->code) { | ||
103 | case MEDIA_BUS_FMT_UYVY8_2X8: | ||
104 | tmp |= 0x1e; /* YUV422 8 bit */ | ||
105 | break; | ||
106 | case MEDIA_BUS_FMT_YUYV8_1_5X8: | ||
107 | tmp |= 0x18; /* YUV420 8 bit */ | ||
108 | break; | ||
109 | case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE: | ||
110 | tmp |= 0x21; /* RGB555 */ | ||
111 | break; | ||
112 | case MEDIA_BUS_FMT_RGB565_2X8_BE: | ||
113 | tmp |= 0x22; /* RGB565 */ | ||
114 | break; | ||
115 | case MEDIA_BUS_FMT_Y8_1X8: | ||
116 | case MEDIA_BUS_FMT_SBGGR8_1X8: | ||
117 | case MEDIA_BUS_FMT_SGRBG8_1X8: | ||
118 | tmp |= 0x2a; /* RAW8 */ | ||
119 | break; | ||
120 | default: | ||
121 | return -EINVAL; | ||
122 | } | ||
123 | |||
124 | iowrite32(tmp, priv->base + SH_CSI2_VCDT); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int sh_csi2_g_mbus_config(struct v4l2_subdev *sd, | ||
130 | struct v4l2_mbus_config *cfg) | ||
131 | { | ||
132 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
133 | |||
134 | if (!priv->mipi_flags) { | ||
135 | struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd); | ||
136 | struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); | ||
137 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | ||
138 | unsigned long common_flags, csi2_flags; | ||
139 | struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2,}; | ||
140 | int ret; | ||
141 | |||
142 | /* Check if we can support this camera */ | ||
143 | csi2_flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | | ||
144 | V4L2_MBUS_CSI2_1_LANE; | ||
145 | |||
146 | switch (pdata->type) { | ||
147 | case SH_CSI2C: | ||
148 | if (priv->client->lanes != 1) | ||
149 | csi2_flags |= V4L2_MBUS_CSI2_2_LANE; | ||
150 | break; | ||
151 | case SH_CSI2I: | ||
152 | switch (priv->client->lanes) { | ||
153 | default: | ||
154 | csi2_flags |= V4L2_MBUS_CSI2_4_LANE; | ||
155 | case 3: | ||
156 | csi2_flags |= V4L2_MBUS_CSI2_3_LANE; | ||
157 | case 2: | ||
158 | csi2_flags |= V4L2_MBUS_CSI2_2_LANE; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | ret = v4l2_subdev_call(client_sd, video, g_mbus_config, &client_cfg); | ||
163 | if (ret == -ENOIOCTLCMD) | ||
164 | common_flags = csi2_flags; | ||
165 | else if (!ret) | ||
166 | common_flags = soc_mbus_config_compatible(&client_cfg, | ||
167 | csi2_flags); | ||
168 | else | ||
169 | common_flags = 0; | ||
170 | |||
171 | if (!common_flags) | ||
172 | return -EINVAL; | ||
173 | |||
174 | /* All good: camera MIPI configuration supported */ | ||
175 | priv->mipi_flags = common_flags; | ||
176 | } | ||
177 | |||
178 | if (cfg) { | ||
179 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
180 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
181 | V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
182 | cfg->type = V4L2_MBUS_PARALLEL; | ||
183 | } | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd, | ||
189 | const struct v4l2_mbus_config *cfg) | ||
190 | { | ||
191 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
192 | struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd); | ||
193 | struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); | ||
194 | struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2,}; | ||
195 | int ret = sh_csi2_g_mbus_config(sd, NULL); | ||
196 | |||
197 | if (ret < 0) | ||
198 | return ret; | ||
199 | |||
200 | pm_runtime_get_sync(&priv->pdev->dev); | ||
201 | |||
202 | sh_csi2_hwinit(priv); | ||
203 | |||
204 | client_cfg.flags = priv->mipi_flags; | ||
205 | |||
206 | return v4l2_subdev_call(client_sd, video, s_mbus_config, &client_cfg); | ||
207 | } | ||
208 | |||
209 | static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = { | ||
210 | .g_mbus_config = sh_csi2_g_mbus_config, | ||
211 | .s_mbus_config = sh_csi2_s_mbus_config, | ||
212 | }; | ||
213 | |||
214 | static struct v4l2_subdev_pad_ops sh_csi2_subdev_pad_ops = { | ||
215 | .set_fmt = sh_csi2_set_fmt, | ||
216 | }; | ||
217 | |||
218 | static void sh_csi2_hwinit(struct sh_csi2 *priv) | ||
219 | { | ||
220 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | ||
221 | __u32 tmp = 0x10; /* Enable MIPI CSI clock lane */ | ||
222 | |||
223 | /* Reflect registers immediately */ | ||
224 | iowrite32(0x00000001, priv->base + SH_CSI2_TREF); | ||
225 | /* reset CSI2 harware */ | ||
226 | iowrite32(0x00000001, priv->base + SH_CSI2_SRST); | ||
227 | udelay(5); | ||
228 | iowrite32(0x00000000, priv->base + SH_CSI2_SRST); | ||
229 | |||
230 | switch (pdata->type) { | ||
231 | case SH_CSI2C: | ||
232 | if (priv->client->lanes == 1) | ||
233 | tmp |= 1; | ||
234 | else | ||
235 | /* Default - both lanes */ | ||
236 | tmp |= 3; | ||
237 | break; | ||
238 | case SH_CSI2I: | ||
239 | if (!priv->client->lanes || priv->client->lanes > 4) | ||
240 | /* Default - all 4 lanes */ | ||
241 | tmp |= 0xf; | ||
242 | else | ||
243 | tmp |= (1 << priv->client->lanes) - 1; | ||
244 | } | ||
245 | |||
246 | if (priv->client->phy == SH_CSI2_PHY_MAIN) | ||
247 | tmp |= 0x8000; | ||
248 | |||
249 | iowrite32(tmp, priv->base + SH_CSI2_PHYCNT); | ||
250 | |||
251 | tmp = 0; | ||
252 | if (pdata->flags & SH_CSI2_ECC) | ||
253 | tmp |= 2; | ||
254 | if (pdata->flags & SH_CSI2_CRC) | ||
255 | tmp |= 1; | ||
256 | iowrite32(tmp, priv->base + SH_CSI2_CHKSUM); | ||
257 | } | ||
258 | |||
259 | static int sh_csi2_client_connect(struct sh_csi2 *priv) | ||
260 | { | ||
261 | struct device *dev = v4l2_get_subdevdata(&priv->subdev); | ||
262 | struct sh_csi2_pdata *pdata = dev->platform_data; | ||
263 | struct soc_camera_device *icd = v4l2_get_subdev_hostdata(&priv->subdev); | ||
264 | int i; | ||
265 | |||
266 | if (priv->client) | ||
267 | return -EBUSY; | ||
268 | |||
269 | for (i = 0; i < pdata->num_clients; i++) | ||
270 | if ((pdata->clients[i].pdev && | ||
271 | &pdata->clients[i].pdev->dev == icd->pdev) || | ||
272 | (icd->control && | ||
273 | strcmp(pdata->clients[i].name, dev_name(icd->control)))) | ||
274 | break; | ||
275 | |||
276 | dev_dbg(dev, "%s(%p): found #%d\n", __func__, dev, i); | ||
277 | |||
278 | if (i == pdata->num_clients) | ||
279 | return -ENODEV; | ||
280 | |||
281 | priv->client = pdata->clients + i; | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static void sh_csi2_client_disconnect(struct sh_csi2 *priv) | ||
287 | { | ||
288 | if (!priv->client) | ||
289 | return; | ||
290 | |||
291 | priv->client = NULL; | ||
292 | |||
293 | pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); | ||
294 | } | ||
295 | |||
296 | static int sh_csi2_s_power(struct v4l2_subdev *sd, int on) | ||
297 | { | ||
298 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
299 | |||
300 | if (on) | ||
301 | return sh_csi2_client_connect(priv); | ||
302 | |||
303 | sh_csi2_client_disconnect(priv); | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops = { | ||
308 | .s_power = sh_csi2_s_power, | ||
309 | }; | ||
310 | |||
311 | static struct v4l2_subdev_ops sh_csi2_subdev_ops = { | ||
312 | .core = &sh_csi2_subdev_core_ops, | ||
313 | .video = &sh_csi2_subdev_video_ops, | ||
314 | .pad = &sh_csi2_subdev_pad_ops, | ||
315 | }; | ||
316 | |||
317 | static int sh_csi2_probe(struct platform_device *pdev) | ||
318 | { | ||
319 | struct resource *res; | ||
320 | unsigned int irq; | ||
321 | int ret; | ||
322 | struct sh_csi2 *priv; | ||
323 | /* Platform data specify the PHY, lanes, ECC, CRC */ | ||
324 | struct sh_csi2_pdata *pdata = pdev->dev.platform_data; | ||
325 | |||
326 | if (!pdata) | ||
327 | return -EINVAL; | ||
328 | |||
329 | priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_csi2), GFP_KERNEL); | ||
330 | if (!priv) | ||
331 | return -ENOMEM; | ||
332 | |||
333 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
334 | /* Interrupt unused so far */ | ||
335 | irq = platform_get_irq(pdev, 0); | ||
336 | |||
337 | if (!res || (int)irq <= 0) { | ||
338 | dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n"); | ||
339 | return -ENODEV; | ||
340 | } | ||
341 | |||
342 | /* TODO: Add support for CSI2I. Careful: different register layout! */ | ||
343 | if (pdata->type != SH_CSI2C) { | ||
344 | dev_err(&pdev->dev, "Only CSI2C supported ATM.\n"); | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | |||
348 | priv->irq = irq; | ||
349 | |||
350 | priv->base = devm_ioremap_resource(&pdev->dev, res); | ||
351 | if (IS_ERR(priv->base)) | ||
352 | return PTR_ERR(priv->base); | ||
353 | |||
354 | priv->pdev = pdev; | ||
355 | priv->subdev.owner = THIS_MODULE; | ||
356 | priv->subdev.dev = &pdev->dev; | ||
357 | platform_set_drvdata(pdev, &priv->subdev); | ||
358 | |||
359 | v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops); | ||
360 | v4l2_set_subdevdata(&priv->subdev, &pdev->dev); | ||
361 | |||
362 | snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.mipi-csi", | ||
363 | dev_name(&pdev->dev)); | ||
364 | |||
365 | ret = v4l2_async_register_subdev(&priv->subdev); | ||
366 | if (ret < 0) | ||
367 | return ret; | ||
368 | |||
369 | pm_runtime_enable(&pdev->dev); | ||
370 | |||
371 | dev_dbg(&pdev->dev, "CSI2 probed.\n"); | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int sh_csi2_remove(struct platform_device *pdev) | ||
377 | { | ||
378 | struct v4l2_subdev *subdev = platform_get_drvdata(pdev); | ||
379 | struct sh_csi2 *priv = container_of(subdev, struct sh_csi2, subdev); | ||
380 | |||
381 | v4l2_async_unregister_subdev(&priv->subdev); | ||
382 | pm_runtime_disable(&pdev->dev); | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | static struct platform_driver __refdata sh_csi2_pdrv = { | ||
388 | .remove = sh_csi2_remove, | ||
389 | .probe = sh_csi2_probe, | ||
390 | .driver = { | ||
391 | .name = "sh-mobile-csi2", | ||
392 | }, | ||
393 | }; | ||
394 | |||
395 | module_platform_driver(sh_csi2_pdrv); | ||
396 | |||
397 | MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver"); | ||
398 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | ||
399 | MODULE_LICENSE("GPL v2"); | ||
400 | MODULE_ALIAS("platform:sh-mobile-csi2"); | ||
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 46c7186f7867..edd1c1de4e33 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c | |||
@@ -581,7 +581,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd, | |||
581 | dev_dbg(icd->pdev, "S_FMT(%c%c%c%c, %ux%u)\n", | 581 | dev_dbg(icd->pdev, "S_FMT(%c%c%c%c, %ux%u)\n", |
582 | pixfmtstr(pix->pixelformat), pix->width, pix->height); | 582 | pixfmtstr(pix->pixelformat), pix->width, pix->height); |
583 | 583 | ||
584 | /* We always call try_fmt() before set_fmt() or set_crop() */ | 584 | /* We always call try_fmt() before set_fmt() or set_selection() */ |
585 | ret = soc_camera_try_fmt(icd, f); | 585 | ret = soc_camera_try_fmt(icd, f); |
586 | if (ret < 0) | 586 | if (ret < 0) |
587 | return ret; | 587 | return ret; |
@@ -1025,72 +1025,6 @@ static int soc_camera_streamoff(struct file *file, void *priv, | |||
1025 | return ret; | 1025 | return ret; |
1026 | } | 1026 | } |
1027 | 1027 | ||
1028 | static int soc_camera_cropcap(struct file *file, void *fh, | ||
1029 | struct v4l2_cropcap *a) | ||
1030 | { | ||
1031 | struct soc_camera_device *icd = file->private_data; | ||
1032 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1033 | |||
1034 | return ici->ops->cropcap(icd, a); | ||
1035 | } | ||
1036 | |||
1037 | static int soc_camera_g_crop(struct file *file, void *fh, | ||
1038 | struct v4l2_crop *a) | ||
1039 | { | ||
1040 | struct soc_camera_device *icd = file->private_data; | ||
1041 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1042 | int ret; | ||
1043 | |||
1044 | ret = ici->ops->get_crop(icd, a); | ||
1045 | |||
1046 | return ret; | ||
1047 | } | ||
1048 | |||
1049 | /* | ||
1050 | * According to the V4L2 API, drivers shall not update the struct v4l2_crop | ||
1051 | * argument with the actual geometry, instead, the user shall use G_CROP to | ||
1052 | * retrieve it. | ||
1053 | */ | ||
1054 | static int soc_camera_s_crop(struct file *file, void *fh, | ||
1055 | const struct v4l2_crop *a) | ||
1056 | { | ||
1057 | struct soc_camera_device *icd = file->private_data; | ||
1058 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1059 | const struct v4l2_rect *rect = &a->c; | ||
1060 | struct v4l2_crop current_crop; | ||
1061 | int ret; | ||
1062 | |||
1063 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1064 | return -EINVAL; | ||
1065 | |||
1066 | dev_dbg(icd->pdev, "S_CROP(%ux%u@%u:%u)\n", | ||
1067 | rect->width, rect->height, rect->left, rect->top); | ||
1068 | |||
1069 | current_crop.type = a->type; | ||
1070 | |||
1071 | /* If get_crop fails, we'll let host and / or client drivers decide */ | ||
1072 | ret = ici->ops->get_crop(icd, ¤t_crop); | ||
1073 | |||
1074 | /* Prohibit window size change with initialised buffers */ | ||
1075 | if (ret < 0) { | ||
1076 | dev_err(icd->pdev, | ||
1077 | "S_CROP denied: getting current crop failed\n"); | ||
1078 | } else if ((a->c.width == current_crop.c.width && | ||
1079 | a->c.height == current_crop.c.height) || | ||
1080 | !is_streaming(ici, icd)) { | ||
1081 | /* same size or not streaming - use .set_crop() */ | ||
1082 | ret = ici->ops->set_crop(icd, a); | ||
1083 | } else if (ici->ops->set_livecrop) { | ||
1084 | ret = ici->ops->set_livecrop(icd, a); | ||
1085 | } else { | ||
1086 | dev_err(icd->pdev, | ||
1087 | "S_CROP denied: queue initialised and sizes differ\n"); | ||
1088 | ret = -EBUSY; | ||
1089 | } | ||
1090 | |||
1091 | return ret; | ||
1092 | } | ||
1093 | |||
1094 | static int soc_camera_g_selection(struct file *file, void *fh, | 1028 | static int soc_camera_g_selection(struct file *file, void *fh, |
1095 | struct v4l2_selection *s) | 1029 | struct v4l2_selection *s) |
1096 | { | 1030 | { |
@@ -1101,9 +1035,6 @@ static int soc_camera_g_selection(struct file *file, void *fh, | |||
1101 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1035 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1102 | return -EINVAL; | 1036 | return -EINVAL; |
1103 | 1037 | ||
1104 | if (!ici->ops->get_selection) | ||
1105 | return -ENOTTY; | ||
1106 | |||
1107 | return ici->ops->get_selection(icd, s); | 1038 | return ici->ops->get_selection(icd, s); |
1108 | } | 1039 | } |
1109 | 1040 | ||
@@ -1135,10 +1066,11 @@ static int soc_camera_s_selection(struct file *file, void *fh, | |||
1135 | return -EBUSY; | 1066 | return -EBUSY; |
1136 | } | 1067 | } |
1137 | 1068 | ||
1138 | if (!ici->ops->set_selection) | 1069 | if (s->target == V4L2_SEL_TGT_CROP && is_streaming(ici, icd) && |
1139 | return -ENOTTY; | 1070 | ici->ops->set_liveselection) |
1140 | 1071 | ret = ici->ops->set_liveselection(icd, s); | |
1141 | ret = ici->ops->set_selection(icd, s); | 1072 | else |
1073 | ret = ici->ops->set_selection(icd, s); | ||
1142 | if (!ret && | 1074 | if (!ret && |
1143 | s->target == V4L2_SEL_TGT_COMPOSE) { | 1075 | s->target == V4L2_SEL_TGT_COMPOSE) { |
1144 | icd->user_width = s->r.width; | 1076 | icd->user_width = s->r.width; |
@@ -1881,23 +1813,40 @@ static int soc_camera_remove(struct soc_camera_device *icd) | |||
1881 | return 0; | 1813 | return 0; |
1882 | } | 1814 | } |
1883 | 1815 | ||
1884 | static int default_cropcap(struct soc_camera_device *icd, | 1816 | static int default_g_selection(struct soc_camera_device *icd, |
1885 | struct v4l2_cropcap *a) | 1817 | struct v4l2_selection *sel) |
1886 | { | 1818 | { |
1887 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1819 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1888 | return v4l2_subdev_call(sd, video, cropcap, a); | 1820 | struct v4l2_subdev_selection sdsel = { |
1889 | } | 1821 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
1822 | .target = sel->target, | ||
1823 | }; | ||
1824 | int ret; | ||
1890 | 1825 | ||
1891 | static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a) | 1826 | ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel); |
1892 | { | 1827 | if (ret) |
1893 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1828 | return ret; |
1894 | return v4l2_subdev_call(sd, video, g_crop, a); | 1829 | sel->r = sdsel.r; |
1830 | return 0; | ||
1895 | } | 1831 | } |
1896 | 1832 | ||
1897 | static int default_s_crop(struct soc_camera_device *icd, const struct v4l2_crop *a) | 1833 | static int default_s_selection(struct soc_camera_device *icd, |
1834 | struct v4l2_selection *sel) | ||
1898 | { | 1835 | { |
1899 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1836 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1900 | return v4l2_subdev_call(sd, video, s_crop, a); | 1837 | struct v4l2_subdev_selection sdsel = { |
1838 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1839 | .target = sel->target, | ||
1840 | .flags = sel->flags, | ||
1841 | .r = sel->r, | ||
1842 | }; | ||
1843 | int ret; | ||
1844 | |||
1845 | ret = v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel); | ||
1846 | if (ret) | ||
1847 | return ret; | ||
1848 | sel->r = sdsel.r; | ||
1849 | return 0; | ||
1901 | } | 1850 | } |
1902 | 1851 | ||
1903 | static int default_g_parm(struct soc_camera_device *icd, | 1852 | static int default_g_parm(struct soc_camera_device *icd, |
@@ -1968,12 +1917,10 @@ int soc_camera_host_register(struct soc_camera_host *ici) | |||
1968 | !ici->v4l2_dev.dev) | 1917 | !ici->v4l2_dev.dev) |
1969 | return -EINVAL; | 1918 | return -EINVAL; |
1970 | 1919 | ||
1971 | if (!ici->ops->set_crop) | 1920 | if (!ici->ops->set_selection) |
1972 | ici->ops->set_crop = default_s_crop; | 1921 | ici->ops->set_selection = default_s_selection; |
1973 | if (!ici->ops->get_crop) | 1922 | if (!ici->ops->get_selection) |
1974 | ici->ops->get_crop = default_g_crop; | 1923 | ici->ops->get_selection = default_g_selection; |
1975 | if (!ici->ops->cropcap) | ||
1976 | ici->ops->cropcap = default_cropcap; | ||
1977 | if (!ici->ops->set_parm) | 1924 | if (!ici->ops->set_parm) |
1978 | ici->ops->set_parm = default_s_parm; | 1925 | ici->ops->set_parm = default_s_parm; |
1979 | if (!ici->ops->get_parm) | 1926 | if (!ici->ops->get_parm) |
@@ -2126,9 +2073,6 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { | |||
2126 | .vidioc_expbuf = soc_camera_expbuf, | 2073 | .vidioc_expbuf = soc_camera_expbuf, |
2127 | .vidioc_streamon = soc_camera_streamon, | 2074 | .vidioc_streamon = soc_camera_streamon, |
2128 | .vidioc_streamoff = soc_camera_streamoff, | 2075 | .vidioc_streamoff = soc_camera_streamoff, |
2129 | .vidioc_cropcap = soc_camera_cropcap, | ||
2130 | .vidioc_g_crop = soc_camera_g_crop, | ||
2131 | .vidioc_s_crop = soc_camera_s_crop, | ||
2132 | .vidioc_g_selection = soc_camera_g_selection, | 2076 | .vidioc_g_selection = soc_camera_g_selection, |
2133 | .vidioc_s_selection = soc_camera_s_selection, | 2077 | .vidioc_s_selection = soc_camera_s_selection, |
2134 | .vidioc_g_parm = soc_camera_g_parm, | 2078 | .vidioc_g_parm = soc_camera_g_parm, |
diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c index a51d2a42998c..534d6c3c6d60 100644 --- a/drivers/media/platform/soc_camera/soc_camera_platform.c +++ b/drivers/media/platform/soc_camera/soc_camera_platform.c | |||
@@ -76,35 +76,27 @@ static int soc_camera_platform_enum_mbus_code(struct v4l2_subdev *sd, | |||
76 | return 0; | 76 | return 0; |
77 | } | 77 | } |
78 | 78 | ||
79 | static int soc_camera_platform_g_crop(struct v4l2_subdev *sd, | 79 | static int soc_camera_platform_get_selection(struct v4l2_subdev *sd, |
80 | struct v4l2_crop *a) | 80 | struct v4l2_subdev_pad_config *cfg, |
81 | { | 81 | struct v4l2_subdev_selection *sel) |
82 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | ||
83 | |||
84 | a->c.left = 0; | ||
85 | a->c.top = 0; | ||
86 | a->c.width = p->format.width; | ||
87 | a->c.height = p->format.height; | ||
88 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int soc_camera_platform_cropcap(struct v4l2_subdev *sd, | ||
94 | struct v4l2_cropcap *a) | ||
95 | { | 82 | { |
96 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | 83 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); |
97 | 84 | ||
98 | a->bounds.left = 0; | 85 | if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
99 | a->bounds.top = 0; | 86 | return -EINVAL; |
100 | a->bounds.width = p->format.width; | ||
101 | a->bounds.height = p->format.height; | ||
102 | a->defrect = a->bounds; | ||
103 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
104 | a->pixelaspect.numerator = 1; | ||
105 | a->pixelaspect.denominator = 1; | ||
106 | 87 | ||
107 | return 0; | 88 | switch (sel->target) { |
89 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
90 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
91 | case V4L2_SEL_TGT_CROP: | ||
92 | sel->r.left = 0; | ||
93 | sel->r.top = 0; | ||
94 | sel->r.width = p->format.width; | ||
95 | sel->r.height = p->format.height; | ||
96 | return 0; | ||
97 | default: | ||
98 | return -EINVAL; | ||
99 | } | ||
108 | } | 100 | } |
109 | 101 | ||
110 | static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd, | 102 | static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd, |
@@ -120,13 +112,12 @@ static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd, | |||
120 | 112 | ||
121 | static struct v4l2_subdev_video_ops platform_subdev_video_ops = { | 113 | static struct v4l2_subdev_video_ops platform_subdev_video_ops = { |
122 | .s_stream = soc_camera_platform_s_stream, | 114 | .s_stream = soc_camera_platform_s_stream, |
123 | .cropcap = soc_camera_platform_cropcap, | ||
124 | .g_crop = soc_camera_platform_g_crop, | ||
125 | .g_mbus_config = soc_camera_platform_g_mbus_config, | 115 | .g_mbus_config = soc_camera_platform_g_mbus_config, |
126 | }; | 116 | }; |
127 | 117 | ||
128 | static const struct v4l2_subdev_pad_ops platform_subdev_pad_ops = { | 118 | static const struct v4l2_subdev_pad_ops platform_subdev_pad_ops = { |
129 | .enum_mbus_code = soc_camera_platform_enum_mbus_code, | 119 | .enum_mbus_code = soc_camera_platform_enum_mbus_code, |
120 | .get_selection = soc_camera_platform_get_selection, | ||
130 | .get_fmt = soc_camera_platform_fill_fmt, | 121 | .get_fmt = soc_camera_platform_fill_fmt, |
131 | .set_fmt = soc_camera_platform_fill_fmt, | 122 | .set_fmt = soc_camera_platform_fill_fmt, |
132 | }; | 123 | }; |
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c index bda29bc1b933..f77252d6ccd3 100644 --- a/drivers/media/platform/soc_camera/soc_scale_crop.c +++ b/drivers/media/platform/soc_camera/soc_scale_crop.c | |||
@@ -40,24 +40,22 @@ static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2) | |||
40 | /* Get and store current client crop */ | 40 | /* Get and store current client crop */ |
41 | int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect) | 41 | int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect) |
42 | { | 42 | { |
43 | struct v4l2_crop crop; | 43 | struct v4l2_subdev_selection sdsel = { |
44 | struct v4l2_cropcap cap; | 44 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
45 | .target = V4L2_SEL_TGT_CROP, | ||
46 | }; | ||
45 | int ret; | 47 | int ret; |
46 | 48 | ||
47 | crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 49 | ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel); |
48 | |||
49 | ret = v4l2_subdev_call(sd, video, g_crop, &crop); | ||
50 | if (!ret) { | 50 | if (!ret) { |
51 | *rect = crop.c; | 51 | *rect = sdsel.r; |
52 | return ret; | 52 | return ret; |
53 | } | 53 | } |
54 | 54 | ||
55 | /* Camera driver doesn't support .g_crop(), assume default rectangle */ | 55 | sdsel.target = V4L2_SEL_TGT_CROP_DEFAULT; |
56 | cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 56 | ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel); |
57 | |||
58 | ret = v4l2_subdev_call(sd, video, cropcap, &cap); | ||
59 | if (!ret) | 57 | if (!ret) |
60 | *rect = cap.defrect; | 58 | *rect = sdsel.r; |
61 | 59 | ||
62 | return ret; | 60 | return ret; |
63 | } | 61 | } |
@@ -93,17 +91,27 @@ static void update_subrect(struct v4l2_rect *rect, struct v4l2_rect *subrect) | |||
93 | * 2. if (1) failed, try to double the client image until we get one big enough | 91 | * 2. if (1) failed, try to double the client image until we get one big enough |
94 | * 3. if (2) failed, try to request the maximum image | 92 | * 3. if (2) failed, try to request the maximum image |
95 | */ | 93 | */ |
96 | int soc_camera_client_s_crop(struct v4l2_subdev *sd, | 94 | int soc_camera_client_s_selection(struct v4l2_subdev *sd, |
97 | struct v4l2_crop *crop, struct v4l2_crop *cam_crop, | 95 | struct v4l2_selection *sel, struct v4l2_selection *cam_sel, |
98 | struct v4l2_rect *target_rect, struct v4l2_rect *subrect) | 96 | struct v4l2_rect *target_rect, struct v4l2_rect *subrect) |
99 | { | 97 | { |
100 | struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c; | 98 | struct v4l2_subdev_selection sdsel = { |
99 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
100 | .target = sel->target, | ||
101 | .flags = sel->flags, | ||
102 | .r = sel->r, | ||
103 | }; | ||
104 | struct v4l2_subdev_selection bounds = { | ||
105 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
106 | .target = V4L2_SEL_TGT_CROP_BOUNDS, | ||
107 | }; | ||
108 | struct v4l2_rect *rect = &sel->r, *cam_rect = &cam_sel->r; | ||
101 | struct device *dev = sd->v4l2_dev->dev; | 109 | struct device *dev = sd->v4l2_dev->dev; |
102 | struct v4l2_cropcap cap; | ||
103 | int ret; | 110 | int ret; |
104 | unsigned int width, height; | 111 | unsigned int width, height; |
105 | 112 | ||
106 | v4l2_subdev_call(sd, video, s_crop, crop); | 113 | v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel); |
114 | sel->r = sdsel.r; | ||
107 | ret = soc_camera_client_g_rect(sd, cam_rect); | 115 | ret = soc_camera_client_g_rect(sd, cam_rect); |
108 | if (ret < 0) | 116 | if (ret < 0) |
109 | return ret; | 117 | return ret; |
@@ -113,29 +121,29 @@ int soc_camera_client_s_crop(struct v4l2_subdev *sd, | |||
113 | * be within camera cropcap bounds | 121 | * be within camera cropcap bounds |
114 | */ | 122 | */ |
115 | if (!memcmp(rect, cam_rect, sizeof(*rect))) { | 123 | if (!memcmp(rect, cam_rect, sizeof(*rect))) { |
116 | /* Even if camera S_CROP failed, but camera rectangle matches */ | 124 | /* Even if camera S_SELECTION failed, but camera rectangle matches */ |
117 | dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n", | 125 | dev_dbg(dev, "Camera S_SELECTION successful for %dx%d@%d:%d\n", |
118 | rect->width, rect->height, rect->left, rect->top); | 126 | rect->width, rect->height, rect->left, rect->top); |
119 | *target_rect = *cam_rect; | 127 | *target_rect = *cam_rect; |
120 | return 0; | 128 | return 0; |
121 | } | 129 | } |
122 | 130 | ||
123 | /* Try to fix cropping, that camera hasn't managed to set */ | 131 | /* Try to fix cropping, that camera hasn't managed to set */ |
124 | dev_geo(dev, "Fix camera S_CROP for %dx%d@%d:%d to %dx%d@%d:%d\n", | 132 | dev_geo(dev, "Fix camera S_SELECTION for %dx%d@%d:%d to %dx%d@%d:%d\n", |
125 | cam_rect->width, cam_rect->height, | 133 | cam_rect->width, cam_rect->height, |
126 | cam_rect->left, cam_rect->top, | 134 | cam_rect->left, cam_rect->top, |
127 | rect->width, rect->height, rect->left, rect->top); | 135 | rect->width, rect->height, rect->left, rect->top); |
128 | 136 | ||
129 | /* We need sensor maximum rectangle */ | 137 | /* We need sensor maximum rectangle */ |
130 | ret = v4l2_subdev_call(sd, video, cropcap, &cap); | 138 | ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &bounds); |
131 | if (ret < 0) | 139 | if (ret < 0) |
132 | return ret; | 140 | return ret; |
133 | 141 | ||
134 | /* Put user requested rectangle within sensor bounds */ | 142 | /* Put user requested rectangle within sensor bounds */ |
135 | soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2, | 143 | soc_camera_limit_side(&rect->left, &rect->width, sdsel.r.left, 2, |
136 | cap.bounds.width); | 144 | bounds.r.width); |
137 | soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4, | 145 | soc_camera_limit_side(&rect->top, &rect->height, sdsel.r.top, 4, |
138 | cap.bounds.height); | 146 | bounds.r.height); |
139 | 147 | ||
140 | /* | 148 | /* |
141 | * Popular special case - some cameras can only handle fixed sizes like | 149 | * Popular special case - some cameras can only handle fixed sizes like |
@@ -150,7 +158,7 @@ int soc_camera_client_s_crop(struct v4l2_subdev *sd, | |||
150 | */ | 158 | */ |
151 | while (!ret && (is_smaller(cam_rect, rect) || | 159 | while (!ret && (is_smaller(cam_rect, rect) || |
152 | is_inside(cam_rect, rect)) && | 160 | is_inside(cam_rect, rect)) && |
153 | (cap.bounds.width > width || cap.bounds.height > height)) { | 161 | (bounds.r.width > width || bounds.r.height > height)) { |
154 | 162 | ||
155 | width *= 2; | 163 | width *= 2; |
156 | height *= 2; | 164 | height *= 2; |
@@ -168,36 +176,40 @@ int soc_camera_client_s_crop(struct v4l2_subdev *sd, | |||
168 | * Instead we just drop to the left and top bounds. | 176 | * Instead we just drop to the left and top bounds. |
169 | */ | 177 | */ |
170 | if (cam_rect->left > rect->left) | 178 | if (cam_rect->left > rect->left) |
171 | cam_rect->left = cap.bounds.left; | 179 | cam_rect->left = bounds.r.left; |
172 | 180 | ||
173 | if (cam_rect->left + cam_rect->width < rect->left + rect->width) | 181 | if (cam_rect->left + cam_rect->width < rect->left + rect->width) |
174 | cam_rect->width = rect->left + rect->width - | 182 | cam_rect->width = rect->left + rect->width - |
175 | cam_rect->left; | 183 | cam_rect->left; |
176 | 184 | ||
177 | if (cam_rect->top > rect->top) | 185 | if (cam_rect->top > rect->top) |
178 | cam_rect->top = cap.bounds.top; | 186 | cam_rect->top = bounds.r.top; |
179 | 187 | ||
180 | if (cam_rect->top + cam_rect->height < rect->top + rect->height) | 188 | if (cam_rect->top + cam_rect->height < rect->top + rect->height) |
181 | cam_rect->height = rect->top + rect->height - | 189 | cam_rect->height = rect->top + rect->height - |
182 | cam_rect->top; | 190 | cam_rect->top; |
183 | 191 | ||
184 | v4l2_subdev_call(sd, video, s_crop, cam_crop); | 192 | sdsel.r = *cam_rect; |
193 | v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel); | ||
194 | *cam_rect = sdsel.r; | ||
185 | ret = soc_camera_client_g_rect(sd, cam_rect); | 195 | ret = soc_camera_client_g_rect(sd, cam_rect); |
186 | dev_geo(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret, | 196 | dev_geo(dev, "Camera S_SELECTION %d for %dx%d@%d:%d\n", ret, |
187 | cam_rect->width, cam_rect->height, | 197 | cam_rect->width, cam_rect->height, |
188 | cam_rect->left, cam_rect->top); | 198 | cam_rect->left, cam_rect->top); |
189 | } | 199 | } |
190 | 200 | ||
191 | /* S_CROP must not modify the rectangle */ | 201 | /* S_SELECTION must not modify the rectangle */ |
192 | if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) { | 202 | if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) { |
193 | /* | 203 | /* |
194 | * The camera failed to configure a suitable cropping, | 204 | * The camera failed to configure a suitable cropping, |
195 | * we cannot use the current rectangle, set to max | 205 | * we cannot use the current rectangle, set to max |
196 | */ | 206 | */ |
197 | *cam_rect = cap.bounds; | 207 | sdsel.r = bounds.r; |
198 | v4l2_subdev_call(sd, video, s_crop, cam_crop); | 208 | v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel); |
209 | *cam_rect = sdsel.r; | ||
210 | |||
199 | ret = soc_camera_client_g_rect(sd, cam_rect); | 211 | ret = soc_camera_client_g_rect(sd, cam_rect); |
200 | dev_geo(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret, | 212 | dev_geo(dev, "Camera S_SELECTION %d for max %dx%d@%d:%d\n", ret, |
201 | cam_rect->width, cam_rect->height, | 213 | cam_rect->width, cam_rect->height, |
202 | cam_rect->left, cam_rect->top); | 214 | cam_rect->left, cam_rect->top); |
203 | } | 215 | } |
@@ -209,7 +221,7 @@ int soc_camera_client_s_crop(struct v4l2_subdev *sd, | |||
209 | 221 | ||
210 | return ret; | 222 | return ret; |
211 | } | 223 | } |
212 | EXPORT_SYMBOL(soc_camera_client_s_crop); | 224 | EXPORT_SYMBOL(soc_camera_client_s_selection); |
213 | 225 | ||
214 | /* Iterative set_fmt, also updates cached client crop on success */ | 226 | /* Iterative set_fmt, also updates cached client crop on success */ |
215 | static int client_set_fmt(struct soc_camera_device *icd, | 227 | static int client_set_fmt(struct soc_camera_device *icd, |
@@ -221,7 +233,10 @@ static int client_set_fmt(struct soc_camera_device *icd, | |||
221 | struct device *dev = icd->parent; | 233 | struct device *dev = icd->parent; |
222 | struct v4l2_mbus_framefmt *mf = &format->format; | 234 | struct v4l2_mbus_framefmt *mf = &format->format; |
223 | unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; | 235 | unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; |
224 | struct v4l2_cropcap cap; | 236 | struct v4l2_subdev_selection sdsel = { |
237 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
238 | .target = V4L2_SEL_TGT_CROP_BOUNDS, | ||
239 | }; | ||
225 | bool host_1to1; | 240 | bool host_1to1; |
226 | int ret; | 241 | int ret; |
227 | 242 | ||
@@ -243,16 +258,14 @@ static int client_set_fmt(struct soc_camera_device *icd, | |||
243 | if (!host_can_scale) | 258 | if (!host_can_scale) |
244 | goto update_cache; | 259 | goto update_cache; |
245 | 260 | ||
246 | cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 261 | ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel); |
247 | |||
248 | ret = v4l2_subdev_call(sd, video, cropcap, &cap); | ||
249 | if (ret < 0) | 262 | if (ret < 0) |
250 | return ret; | 263 | return ret; |
251 | 264 | ||
252 | if (max_width > cap.bounds.width) | 265 | if (max_width > sdsel.r.width) |
253 | max_width = cap.bounds.width; | 266 | max_width = sdsel.r.width; |
254 | if (max_height > cap.bounds.height) | 267 | if (max_height > sdsel.r.height) |
255 | max_height = cap.bounds.height; | 268 | max_height = sdsel.r.height; |
256 | 269 | ||
257 | /* Camera set a format, but geometry is not precise, try to improve */ | 270 | /* Camera set a format, but geometry is not precise, try to improve */ |
258 | tmp_w = mf->width; | 271 | tmp_w = mf->width; |
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.h b/drivers/media/platform/soc_camera/soc_scale_crop.h index 184a30dff541..9ca469312a1f 100644 --- a/drivers/media/platform/soc_camera/soc_scale_crop.h +++ b/drivers/media/platform/soc_camera/soc_scale_crop.h | |||
@@ -16,7 +16,7 @@ | |||
16 | 16 | ||
17 | struct soc_camera_device; | 17 | struct soc_camera_device; |
18 | 18 | ||
19 | struct v4l2_crop; | 19 | struct v4l2_selection; |
20 | struct v4l2_mbus_framefmt; | 20 | struct v4l2_mbus_framefmt; |
21 | struct v4l2_pix_format; | 21 | struct v4l2_pix_format; |
22 | struct v4l2_rect; | 22 | struct v4l2_rect; |
@@ -31,8 +31,8 @@ static inline unsigned int soc_camera_shift_scale(unsigned int size, | |||
31 | #define soc_camera_calc_scale(in, shift, out) soc_camera_shift_scale(in, shift, out) | 31 | #define soc_camera_calc_scale(in, shift, out) soc_camera_shift_scale(in, shift, out) |
32 | 32 | ||
33 | int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); | 33 | int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); |
34 | int soc_camera_client_s_crop(struct v4l2_subdev *sd, | 34 | int soc_camera_client_s_selection(struct v4l2_subdev *sd, |
35 | struct v4l2_crop *crop, struct v4l2_crop *cam_crop, | 35 | struct v4l2_selection *sel, struct v4l2_selection *cam_sel, |
36 | struct v4l2_rect *target_rect, struct v4l2_rect *subrect); | 36 | struct v4l2_rect *target_rect, struct v4l2_rect *subrect); |
37 | int soc_camera_client_scale(struct soc_camera_device *icd, | 37 | int soc_camera_client_scale(struct soc_camera_device *icd, |
38 | struct v4l2_rect *rect, struct v4l2_rect *subrect, | 38 | struct v4l2_rect *rect, struct v4l2_rect *subrect, |
diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index 3b1ac687d0df..45f82b5ddd77 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c | |||
@@ -527,7 +527,7 @@ static void bdisp_stop_streaming(struct vb2_queue *q) | |||
527 | pm_runtime_put(ctx->bdisp_dev->dev); | 527 | pm_runtime_put(ctx->bdisp_dev->dev); |
528 | } | 528 | } |
529 | 529 | ||
530 | static struct vb2_ops bdisp_qops = { | 530 | static const struct vb2_ops bdisp_qops = { |
531 | .queue_setup = bdisp_queue_setup, | 531 | .queue_setup = bdisp_queue_setup, |
532 | .buf_prepare = bdisp_buf_prepare, | 532 | .buf_prepare = bdisp_buf_prepare, |
533 | .buf_queue = bdisp_buf_queue, | 533 | .buf_queue = bdisp_buf_queue, |
diff --git a/drivers/media/platform/sti/hva/Makefile b/drivers/media/platform/sti/hva/Makefile new file mode 100644 index 000000000000..ffb69cebaef3 --- /dev/null +++ b/drivers/media/platform/sti/hva/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-$(CONFIG_VIDEO_STI_HVA) := st-hva.o | ||
2 | st-hva-y := hva-v4l2.o hva-hw.o hva-mem.o hva-h264.o | ||
diff --git a/drivers/media/platform/sti/hva/hva-h264.c b/drivers/media/platform/sti/hva/hva-h264.c new file mode 100644 index 000000000000..8cc8467c0cd3 --- /dev/null +++ b/drivers/media/platform/sti/hva/hva-h264.c | |||
@@ -0,0 +1,1050 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2015 | ||
3 | * Authors: Yannick Fertre <yannick.fertre@st.com> | ||
4 | * Hugues Fruchet <hugues.fruchet@st.com> | ||
5 | * License terms: GNU General Public License (GPL), version 2 | ||
6 | */ | ||
7 | |||
8 | #include "hva.h" | ||
9 | #include "hva-hw.h" | ||
10 | |||
11 | #define MAX_SPS_PPS_SIZE 128 | ||
12 | |||
13 | #define BITSTREAM_OFFSET_MASK 0x7F | ||
14 | |||
15 | /* video max size*/ | ||
16 | #define H264_MAX_SIZE_W 1920 | ||
17 | #define H264_MAX_SIZE_H 1920 | ||
18 | |||
19 | /* macroBlocs number (width & height) */ | ||
20 | #define MB_W(w) ((w + 0xF) / 0x10) | ||
21 | #define MB_H(h) ((h + 0xF) / 0x10) | ||
22 | |||
23 | /* formula to get temporal or spatial data size */ | ||
24 | #define DATA_SIZE(w, h) (MB_W(w) * MB_H(h) * 16) | ||
25 | |||
26 | #define SEARCH_WINDOW_BUFFER_MAX_SIZE(w) ((4 * MB_W(w) + 42) * 256 * 3 / 2) | ||
27 | #define CABAC_CONTEXT_BUFFER_MAX_SIZE(w) (MB_W(w) * 16) | ||
28 | #define CTX_MB_BUFFER_MAX_SIZE(w) (MB_W(w) * 16 * 8) | ||
29 | #define SLICE_HEADER_SIZE (4 * 16) | ||
30 | #define BRC_DATA_SIZE (5 * 16) | ||
31 | |||
32 | /* source buffer copy in YUV 420 MB-tiled format with size=16*256*3/2 */ | ||
33 | #define CURRENT_WINDOW_BUFFER_MAX_SIZE (16 * 256 * 3 / 2) | ||
34 | |||
35 | /* | ||
36 | * 4 lines of pixels (in Luma, Chroma blue and Chroma red) of top MB | ||
37 | * for deblocking with size=4*16*MBx*2 | ||
38 | */ | ||
39 | #define LOCAL_RECONSTRUCTED_BUFFER_MAX_SIZE(w) (4 * 16 * MB_W(w) * 2) | ||
40 | |||
41 | /* factor for bitrate and cpb buffer size max values if profile >= high */ | ||
42 | #define H264_FACTOR_HIGH 1200 | ||
43 | |||
44 | /* factor for bitrate and cpb buffer size max values if profile < high */ | ||
45 | #define H264_FACTOR_BASELINE 1000 | ||
46 | |||
47 | /* number of bytes for NALU_TYPE_FILLER_DATA header and footer */ | ||
48 | #define H264_FILLER_DATA_SIZE 6 | ||
49 | |||
50 | struct h264_profile { | ||
51 | enum v4l2_mpeg_video_h264_level level; | ||
52 | u32 max_mb_per_seconds; | ||
53 | u32 max_frame_size; | ||
54 | u32 max_bitrate; | ||
55 | u32 max_cpb_size; | ||
56 | u32 min_comp_ratio; | ||
57 | }; | ||
58 | |||
59 | static const struct h264_profile h264_infos_list[] = { | ||
60 | {V4L2_MPEG_VIDEO_H264_LEVEL_1_0, 1485, 99, 64, 175, 2}, | ||
61 | {V4L2_MPEG_VIDEO_H264_LEVEL_1B, 1485, 99, 128, 350, 2}, | ||
62 | {V4L2_MPEG_VIDEO_H264_LEVEL_1_1, 3000, 396, 192, 500, 2}, | ||
63 | {V4L2_MPEG_VIDEO_H264_LEVEL_1_2, 6000, 396, 384, 1000, 2}, | ||
64 | {V4L2_MPEG_VIDEO_H264_LEVEL_1_3, 11880, 396, 768, 2000, 2}, | ||
65 | {V4L2_MPEG_VIDEO_H264_LEVEL_2_0, 11880, 396, 2000, 2000, 2}, | ||
66 | {V4L2_MPEG_VIDEO_H264_LEVEL_2_1, 19800, 792, 4000, 4000, 2}, | ||
67 | {V4L2_MPEG_VIDEO_H264_LEVEL_2_2, 20250, 1620, 4000, 4000, 2}, | ||
68 | {V4L2_MPEG_VIDEO_H264_LEVEL_3_0, 40500, 1620, 10000, 10000, 2}, | ||
69 | {V4L2_MPEG_VIDEO_H264_LEVEL_3_1, 108000, 3600, 14000, 14000, 4}, | ||
70 | {V4L2_MPEG_VIDEO_H264_LEVEL_3_2, 216000, 5120, 20000, 20000, 4}, | ||
71 | {V4L2_MPEG_VIDEO_H264_LEVEL_4_0, 245760, 8192, 20000, 25000, 4}, | ||
72 | {V4L2_MPEG_VIDEO_H264_LEVEL_4_1, 245760, 8192, 50000, 62500, 2}, | ||
73 | {V4L2_MPEG_VIDEO_H264_LEVEL_4_2, 522240, 8704, 50000, 62500, 2}, | ||
74 | {V4L2_MPEG_VIDEO_H264_LEVEL_5_0, 589824, 22080, 135000, 135000, 2}, | ||
75 | {V4L2_MPEG_VIDEO_H264_LEVEL_5_1, 983040, 36864, 240000, 240000, 2} | ||
76 | }; | ||
77 | |||
78 | enum hva_brc_type { | ||
79 | BRC_TYPE_NONE = 0, | ||
80 | BRC_TYPE_CBR = 1, | ||
81 | BRC_TYPE_VBR = 2, | ||
82 | BRC_TYPE_VBR_LOW_DELAY = 3 | ||
83 | }; | ||
84 | |||
85 | enum hva_entropy_coding_mode { | ||
86 | CAVLC = 0, | ||
87 | CABAC = 1 | ||
88 | }; | ||
89 | |||
90 | enum hva_picture_coding_type { | ||
91 | PICTURE_CODING_TYPE_I = 0, | ||
92 | PICTURE_CODING_TYPE_P = 1, | ||
93 | PICTURE_CODING_TYPE_B = 2 | ||
94 | }; | ||
95 | |||
96 | enum hva_h264_sampling_mode { | ||
97 | SAMPLING_MODE_NV12 = 0, | ||
98 | SAMPLING_MODE_UYVY = 1, | ||
99 | SAMPLING_MODE_RGB3 = 3, | ||
100 | SAMPLING_MODE_XRGB4 = 4, | ||
101 | SAMPLING_MODE_NV21 = 8, | ||
102 | SAMPLING_MODE_VYUY = 9, | ||
103 | SAMPLING_MODE_BGR3 = 11, | ||
104 | SAMPLING_MODE_XBGR4 = 12, | ||
105 | SAMPLING_MODE_RGBX4 = 20, | ||
106 | SAMPLING_MODE_BGRX4 = 28 | ||
107 | }; | ||
108 | |||
109 | enum hva_h264_nalu_type { | ||
110 | NALU_TYPE_UNKNOWN = 0, | ||
111 | NALU_TYPE_SLICE = 1, | ||
112 | NALU_TYPE_SLICE_DPA = 2, | ||
113 | NALU_TYPE_SLICE_DPB = 3, | ||
114 | NALU_TYPE_SLICE_DPC = 4, | ||
115 | NALU_TYPE_SLICE_IDR = 5, | ||
116 | NALU_TYPE_SEI = 6, | ||
117 | NALU_TYPE_SPS = 7, | ||
118 | NALU_TYPE_PPS = 8, | ||
119 | NALU_TYPE_AU_DELIMITER = 9, | ||
120 | NALU_TYPE_SEQ_END = 10, | ||
121 | NALU_TYPE_STREAM_END = 11, | ||
122 | NALU_TYPE_FILLER_DATA = 12, | ||
123 | NALU_TYPE_SPS_EXT = 13, | ||
124 | NALU_TYPE_PREFIX_UNIT = 14, | ||
125 | NALU_TYPE_SUBSET_SPS = 15, | ||
126 | NALU_TYPE_SLICE_AUX = 19, | ||
127 | NALU_TYPE_SLICE_EXT = 20 | ||
128 | }; | ||
129 | |||
130 | enum hva_h264_sei_payload_type { | ||
131 | SEI_BUFFERING_PERIOD = 0, | ||
132 | SEI_PICTURE_TIMING = 1, | ||
133 | SEI_STEREO_VIDEO_INFO = 21, | ||
134 | SEI_FRAME_PACKING_ARRANGEMENT = 45 | ||
135 | }; | ||
136 | |||
137 | /** | ||
138 | * stereo Video Info struct | ||
139 | */ | ||
140 | struct hva_h264_stereo_video_sei { | ||
141 | u8 field_views_flag; | ||
142 | u8 top_field_is_left_view_flag; | ||
143 | u8 current_frame_is_left_view_flag; | ||
144 | u8 next_frame_is_second_view_flag; | ||
145 | u8 left_view_self_contained_flag; | ||
146 | u8 right_view_self_contained_flag; | ||
147 | }; | ||
148 | |||
149 | /** | ||
150 | * @frame_width: width in pixels of the buffer containing the input frame | ||
151 | * @frame_height: height in pixels of the buffer containing the input frame | ||
152 | * @frame_num: the parameter to be written in the slice header | ||
153 | * @picture_coding_type: type I, P or B | ||
154 | * @pic_order_cnt_type: POC mode, as defined in H264 std : can be 0,1,2 | ||
155 | * @first_picture_in_sequence: flag telling to encoder that this is the | ||
156 | * first picture in a video sequence. | ||
157 | * Used for VBR | ||
158 | * @slice_size_type: 0 = no constraint to close the slice | ||
159 | * 1= a slice is closed as soon as the slice_mb_size limit | ||
160 | * is reached | ||
161 | * 2= a slice is closed as soon as the slice_byte_size limit | ||
162 | * is reached | ||
163 | * 3= a slice is closed as soon as either the slice_byte_size | ||
164 | * limit or the slice_mb_size limit is reached | ||
165 | * @slice_mb_size: defines the slice size in number of macroblocks | ||
166 | * (used when slice_size_type=1 or slice_size_type=3) | ||
167 | * @ir_param_option: defines the number of macroblocks per frame to be | ||
168 | * refreshed by AIR algorithm OR the refresh period | ||
169 | * by CIR algorithm | ||
170 | * @intra_refresh_type: enables the adaptive intra refresh algorithm. | ||
171 | * Disable=0 / Adaptative=1 and Cycle=2 as intra refresh | ||
172 | * @use_constrained_intra_flag: constrained_intra_pred_flag from PPS | ||
173 | * @transform_mode: controls the use of 4x4/8x8 transform mode | ||
174 | * @disable_deblocking_filter_idc: | ||
175 | * 0: specifies that all luma and chroma block edges of | ||
176 | * the slice are filtered. | ||
177 | * 1: specifies that deblocking is disabled for all block | ||
178 | * edges of the slice. | ||
179 | * 2: specifies that all luma and chroma block edges of | ||
180 | * the slice are filtered with exception of the block edges | ||
181 | * that coincide with slice boundaries | ||
182 | * @slice_alpha_c0_offset_div2: to be written in slice header, | ||
183 | * controls deblocking | ||
184 | * @slice_beta_offset_div2: to be written in slice header, | ||
185 | * controls deblocking | ||
186 | * @encoder_complexity: encoder complexity control (IME). | ||
187 | * 0 = I_16x16, P_16x16, Full ME Complexity | ||
188 | * 1 = I_16x16, I_NxN, P_16x16, Full ME Complexity | ||
189 | * 2 = I_16x16, I_NXN, P_16x16, P_WxH, Full ME Complexity | ||
190 | * 4 = I_16x16, P_16x16, Reduced ME Complexity | ||
191 | * 5 = I_16x16, I_NxN, P_16x16, Reduced ME Complexity | ||
192 | * 6 = I_16x16, I_NXN, P_16x16, P_WxH, Reduced ME Complexity | ||
193 | * @chroma_qp_index_offset: coming from picture parameter set | ||
194 | * (PPS see [H.264 STD] 7.4.2.2) | ||
195 | * @entropy_coding_mode: entropy coding mode. | ||
196 | * 0 = CAVLC | ||
197 | * 1 = CABAC | ||
198 | * @brc_type: selects the bit-rate control algorithm | ||
199 | * 0 = constant Qp, (no BRC) | ||
200 | * 1 = CBR | ||
201 | * 2 = VBR | ||
202 | * @quant: Quantization param used in case of fix QP encoding (no BRC) | ||
203 | * @non_VCL_NALU_Size: size of non-VCL NALUs (SPS, PPS, filler), | ||
204 | * used by BRC | ||
205 | * @cpb_buffer_size: size of Coded Picture Buffer, used by BRC | ||
206 | * @bit_rate: target bitrate, for BRC | ||
207 | * @qp_min: min QP threshold | ||
208 | * @qp_max: max QP threshold | ||
209 | * @framerate_num: target framerate numerator , used by BRC | ||
210 | * @framerate_den: target framerate denomurator , used by BRC | ||
211 | * @delay: End-to-End Initial Delay | ||
212 | * @strict_HRD_compliancy: flag for HDR compliancy (1) | ||
213 | * May impact quality encoding | ||
214 | * @addr_source_buffer: address of input frame buffer for current frame | ||
215 | * @addr_fwd_Ref_Buffer: address of reference frame buffer | ||
216 | * @addr_rec_buffer: address of reconstructed frame buffer | ||
217 | * @addr_output_bitstream_start: output bitstream start address | ||
218 | * @addr_output_bitstream_end: output bitstream end address | ||
219 | * @addr_external_sw : address of external search window | ||
220 | * @addr_lctx : address of context picture buffer | ||
221 | * @addr_local_rec_buffer: address of local reconstructed buffer | ||
222 | * @addr_spatial_context: address of spatial context buffer | ||
223 | * @bitstream_offset: offset in bits between aligned bitstream start | ||
224 | * address and first bit to be written by HVA. | ||
225 | * Range value is [0..63] | ||
226 | * @sampling_mode: Input picture format . | ||
227 | * 0: YUV420 semi_planar Interleaved | ||
228 | * 1: YUV422 raster Interleaved | ||
229 | * @addr_param_out: address of output parameters structure | ||
230 | * @addr_scaling_matrix: address to the coefficient of | ||
231 | * the inverse scaling matrix | ||
232 | * @addr_scaling_matrix_dir: address to the coefficient of | ||
233 | * the direct scaling matrix | ||
234 | * @addr_cabac_context_buffer: address of cabac context buffer | ||
235 | * @GmvX: Input information about the horizontal global displacement of | ||
236 | * the encoded frame versus the previous one | ||
237 | * @GmvY: Input information about the vertical global displacement of | ||
238 | * the encoded frame versus the previous one | ||
239 | * @window_width: width in pixels of the window to be encoded inside | ||
240 | * the input frame | ||
241 | * @window_height: width in pixels of the window to be encoded inside | ||
242 | * the input frame | ||
243 | * @window_horizontal_offset: horizontal offset in pels for input window | ||
244 | * within input frame | ||
245 | * @window_vertical_offset: vertical offset in pels for input window | ||
246 | * within input frame | ||
247 | * @addr_roi: Map of QP offset for the Region of Interest algorithm and | ||
248 | * also used for Error map. | ||
249 | * Bit 0-6 used for qp offset (value -64 to 63). | ||
250 | * Bit 7 used to force intra | ||
251 | * @addr_slice_header: address to slice header | ||
252 | * @slice_header_size_in_bits: size in bits of the Slice header | ||
253 | * @slice_header_offset0: Slice header offset where to insert | ||
254 | * first_Mb_in_slice | ||
255 | * @slice_header_offset1: Slice header offset where to insert | ||
256 | * slice_qp_delta | ||
257 | * @slice_header_offset2: Slice header offset where to insert | ||
258 | * num_MBs_in_slice | ||
259 | * @slice_synchro_enable: enable "slice ready" interrupt after each slice | ||
260 | * @max_slice_number: Maximum number of slice in a frame | ||
261 | * (0 is strictly forbidden) | ||
262 | * @rgb2_yuv_y_coeff: Four coefficients (C0C1C2C3) to convert from RGB to | ||
263 | * YUV for the Y component. | ||
264 | * Y = C0*R + C1*G + C2*B + C3 (C0 is on byte 0) | ||
265 | * @rgb2_yuv_u_coeff: four coefficients (C0C1C2C3) to convert from RGB to | ||
266 | * YUV for the Y component. | ||
267 | * Y = C0*R + C1*G + C2*B + C3 (C0 is on byte 0) | ||
268 | * @rgb2_yuv_v_coeff: Four coefficients (C0C1C2C3) to convert from RGB to | ||
269 | * YUV for the U (Cb) component. | ||
270 | * U = C0*R + C1*G + C2*B + C3 (C0 is on byte 0) | ||
271 | * @slice_byte_size: maximum slice size in bytes | ||
272 | * (used when slice_size_type=2 or slice_size_type=3) | ||
273 | * @max_air_intra_mb_nb: Maximum number of intra macroblock in a frame | ||
274 | * for the AIR algorithm | ||
275 | * @brc_no_skip: Disable skipping in the Bitrate Controller | ||
276 | * @addr_brc_in_out_parameter: address of static buffer for BRC parameters | ||
277 | */ | ||
278 | struct hva_h264_td { | ||
279 | u16 frame_width; | ||
280 | u16 frame_height; | ||
281 | u32 frame_num; | ||
282 | u16 picture_coding_type; | ||
283 | u16 reserved1; | ||
284 | u16 pic_order_cnt_type; | ||
285 | u16 first_picture_in_sequence; | ||
286 | u16 slice_size_type; | ||
287 | u16 reserved2; | ||
288 | u32 slice_mb_size; | ||
289 | u16 ir_param_option; | ||
290 | u16 intra_refresh_type; | ||
291 | u16 use_constrained_intra_flag; | ||
292 | u16 transform_mode; | ||
293 | u16 disable_deblocking_filter_idc; | ||
294 | s16 slice_alpha_c0_offset_div2; | ||
295 | s16 slice_beta_offset_div2; | ||
296 | u16 encoder_complexity; | ||
297 | s16 chroma_qp_index_offset; | ||
298 | u16 entropy_coding_mode; | ||
299 | u16 brc_type; | ||
300 | u16 quant; | ||
301 | u32 non_vcl_nalu_size; | ||
302 | u32 cpb_buffer_size; | ||
303 | u32 bit_rate; | ||
304 | u16 qp_min; | ||
305 | u16 qp_max; | ||
306 | u16 framerate_num; | ||
307 | u16 framerate_den; | ||
308 | u16 delay; | ||
309 | u16 strict_hrd_compliancy; | ||
310 | u32 addr_source_buffer; | ||
311 | u32 addr_fwd_ref_buffer; | ||
312 | u32 addr_rec_buffer; | ||
313 | u32 addr_output_bitstream_start; | ||
314 | u32 addr_output_bitstream_end; | ||
315 | u32 addr_external_sw; | ||
316 | u32 addr_lctx; | ||
317 | u32 addr_local_rec_buffer; | ||
318 | u32 addr_spatial_context; | ||
319 | u16 bitstream_offset; | ||
320 | u16 sampling_mode; | ||
321 | u32 addr_param_out; | ||
322 | u32 addr_scaling_matrix; | ||
323 | u32 addr_scaling_matrix_dir; | ||
324 | u32 addr_cabac_context_buffer; | ||
325 | u32 reserved3; | ||
326 | u32 reserved4; | ||
327 | s16 gmv_x; | ||
328 | s16 gmv_y; | ||
329 | u16 window_width; | ||
330 | u16 window_height; | ||
331 | u16 window_horizontal_offset; | ||
332 | u16 window_vertical_offset; | ||
333 | u32 addr_roi; | ||
334 | u32 addr_slice_header; | ||
335 | u16 slice_header_size_in_bits; | ||
336 | u16 slice_header_offset0; | ||
337 | u16 slice_header_offset1; | ||
338 | u16 slice_header_offset2; | ||
339 | u32 reserved5; | ||
340 | u32 reserved6; | ||
341 | u16 reserved7; | ||
342 | u16 reserved8; | ||
343 | u16 slice_synchro_enable; | ||
344 | u16 max_slice_number; | ||
345 | u32 rgb2_yuv_y_coeff; | ||
346 | u32 rgb2_yuv_u_coeff; | ||
347 | u32 rgb2_yuv_v_coeff; | ||
348 | u32 slice_byte_size; | ||
349 | u16 max_air_intra_mb_nb; | ||
350 | u16 brc_no_skip; | ||
351 | u32 addr_temporal_context; | ||
352 | u32 addr_brc_in_out_parameter; | ||
353 | }; | ||
354 | |||
355 | /** | ||
356 | * @ slice_size: slice size | ||
357 | * @ slice_start_time: start time | ||
358 | * @ slice_stop_time: stop time | ||
359 | * @ slice_num: slice number | ||
360 | */ | ||
361 | struct hva_h264_slice_po { | ||
362 | u32 slice_size; | ||
363 | u32 slice_start_time; | ||
364 | u32 slice_end_time; | ||
365 | u32 slice_num; | ||
366 | }; | ||
367 | |||
368 | /** | ||
369 | * @ bitstream_size: bitstream size | ||
370 | * @ dct_bitstream_size: dtc bitstream size | ||
371 | * @ stuffing_bits: number of stuffing bits inserted by the encoder | ||
372 | * @ removal_time: removal time of current frame (nb of ticks 1/framerate) | ||
373 | * @ hvc_start_time: hvc start time | ||
374 | * @ hvc_stop_time: hvc stop time | ||
375 | * @ slice_count: slice count | ||
376 | */ | ||
377 | struct hva_h264_po { | ||
378 | u32 bitstream_size; | ||
379 | u32 dct_bitstream_size; | ||
380 | u32 stuffing_bits; | ||
381 | u32 removal_time; | ||
382 | u32 hvc_start_time; | ||
383 | u32 hvc_stop_time; | ||
384 | u32 slice_count; | ||
385 | u32 reserved0; | ||
386 | struct hva_h264_slice_po slice_params[16]; | ||
387 | }; | ||
388 | |||
389 | struct hva_h264_task { | ||
390 | struct hva_h264_td td; | ||
391 | struct hva_h264_po po; | ||
392 | }; | ||
393 | |||
394 | /** | ||
395 | * @seq_info: sequence information buffer | ||
396 | * @ref_frame: reference frame buffer | ||
397 | * @rec_frame: reconstructed frame buffer | ||
398 | * @task: task descriptor | ||
399 | */ | ||
400 | struct hva_h264_ctx { | ||
401 | struct hva_buffer *seq_info; | ||
402 | struct hva_buffer *ref_frame; | ||
403 | struct hva_buffer *rec_frame; | ||
404 | struct hva_buffer *task; | ||
405 | }; | ||
406 | |||
407 | static int hva_h264_fill_slice_header(struct hva_ctx *pctx, | ||
408 | u8 *slice_header_addr, | ||
409 | struct hva_controls *ctrls, | ||
410 | int frame_num, | ||
411 | u16 *header_size, | ||
412 | u16 *header_offset0, | ||
413 | u16 *header_offset1, | ||
414 | u16 *header_offset2) | ||
415 | { | ||
416 | /* | ||
417 | * with this HVA hardware version, part of the slice header is computed | ||
418 | * on host and part by hardware. | ||
419 | * The part of host is precomputed and available through this array. | ||
420 | */ | ||
421 | struct device *dev = ctx_to_dev(pctx); | ||
422 | int cabac = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC; | ||
423 | const unsigned char slice_header[] = { 0x00, 0x00, 0x00, 0x01, | ||
424 | 0x41, 0x34, 0x07, 0x00}; | ||
425 | int idr_pic_id = frame_num % 2; | ||
426 | enum hva_picture_coding_type type; | ||
427 | u32 frame_order = frame_num % ctrls->gop_size; | ||
428 | |||
429 | if (!(frame_num % ctrls->gop_size)) | ||
430 | type = PICTURE_CODING_TYPE_I; | ||
431 | else | ||
432 | type = PICTURE_CODING_TYPE_P; | ||
433 | |||
434 | memcpy(slice_header_addr, slice_header, sizeof(slice_header)); | ||
435 | |||
436 | *header_size = 56; | ||
437 | *header_offset0 = 40; | ||
438 | *header_offset1 = 13; | ||
439 | *header_offset2 = 0; | ||
440 | |||
441 | if (type == PICTURE_CODING_TYPE_I) { | ||
442 | slice_header_addr[4] = 0x65; | ||
443 | slice_header_addr[5] = 0x11; | ||
444 | |||
445 | /* toggle the I frame */ | ||
446 | if ((frame_num / ctrls->gop_size) % 2) { | ||
447 | *header_size += 4; | ||
448 | *header_offset1 += 4; | ||
449 | slice_header_addr[6] = 0x04; | ||
450 | slice_header_addr[7] = 0x70; | ||
451 | |||
452 | } else { | ||
453 | *header_size += 2; | ||
454 | *header_offset1 += 2; | ||
455 | slice_header_addr[6] = 0x09; | ||
456 | slice_header_addr[7] = 0xC0; | ||
457 | } | ||
458 | } else { | ||
459 | if (ctrls->entropy_mode == cabac) { | ||
460 | *header_size += 1; | ||
461 | *header_offset1 += 1; | ||
462 | slice_header_addr[7] = 0x80; | ||
463 | } | ||
464 | /* | ||
465 | * update slice header with P frame order | ||
466 | * frame order is limited to 16 (coded on 4bits only) | ||
467 | */ | ||
468 | slice_header_addr[5] += ((frame_order & 0x0C) >> 2); | ||
469 | slice_header_addr[6] += ((frame_order & 0x03) << 6); | ||
470 | } | ||
471 | |||
472 | dev_dbg(dev, | ||
473 | "%s %s slice header order %d idrPicId %d header size %d\n", | ||
474 | pctx->name, __func__, frame_order, idr_pic_id, *header_size); | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static int hva_h264_fill_data_nal(struct hva_ctx *pctx, | ||
479 | unsigned int stuffing_bytes, u8 *addr, | ||
480 | unsigned int stream_size, unsigned int *size) | ||
481 | { | ||
482 | struct device *dev = ctx_to_dev(pctx); | ||
483 | const u8 start[] = { 0x00, 0x00, 0x00, 0x01 }; | ||
484 | |||
485 | dev_dbg(dev, "%s %s stuffing bytes %d\n", pctx->name, __func__, | ||
486 | stuffing_bytes); | ||
487 | |||
488 | if ((*size + stuffing_bytes + H264_FILLER_DATA_SIZE) > stream_size) { | ||
489 | dev_dbg(dev, "%s %s too many stuffing bytes %d\n", | ||
490 | pctx->name, __func__, stuffing_bytes); | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | /* start code */ | ||
495 | memcpy(addr + *size, start, sizeof(start)); | ||
496 | *size += sizeof(start); | ||
497 | |||
498 | /* nal_unit_type */ | ||
499 | addr[*size] = NALU_TYPE_FILLER_DATA; | ||
500 | *size += 1; | ||
501 | |||
502 | memset(addr + *size, 0xff, stuffing_bytes); | ||
503 | *size += stuffing_bytes; | ||
504 | |||
505 | addr[*size] = 0x80; | ||
506 | *size += 1; | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static int hva_h264_fill_sei_nal(struct hva_ctx *pctx, | ||
512 | enum hva_h264_sei_payload_type type, | ||
513 | u8 *addr, u32 *size) | ||
514 | { | ||
515 | struct device *dev = ctx_to_dev(pctx); | ||
516 | const u8 start[] = { 0x00, 0x00, 0x00, 0x01 }; | ||
517 | struct hva_h264_stereo_video_sei info; | ||
518 | u8 offset = 7; | ||
519 | u8 msg = 0; | ||
520 | |||
521 | /* start code */ | ||
522 | memcpy(addr + *size, start, sizeof(start)); | ||
523 | *size += sizeof(start); | ||
524 | |||
525 | /* nal_unit_type */ | ||
526 | addr[*size] = NALU_TYPE_SEI; | ||
527 | *size += 1; | ||
528 | |||
529 | /* payload type */ | ||
530 | addr[*size] = type; | ||
531 | *size += 1; | ||
532 | |||
533 | switch (type) { | ||
534 | case SEI_STEREO_VIDEO_INFO: | ||
535 | memset(&info, 0, sizeof(info)); | ||
536 | |||
537 | /* set to top/bottom frame packing arrangement */ | ||
538 | info.field_views_flag = 1; | ||
539 | info.top_field_is_left_view_flag = 1; | ||
540 | |||
541 | /* payload size */ | ||
542 | addr[*size] = 1; | ||
543 | *size += 1; | ||
544 | |||
545 | /* payload */ | ||
546 | msg = info.field_views_flag << offset--; | ||
547 | |||
548 | if (info.field_views_flag) { | ||
549 | msg |= info.top_field_is_left_view_flag << | ||
550 | offset--; | ||
551 | } else { | ||
552 | msg |= info.current_frame_is_left_view_flag << | ||
553 | offset--; | ||
554 | msg |= info.next_frame_is_second_view_flag << | ||
555 | offset--; | ||
556 | } | ||
557 | msg |= info.left_view_self_contained_flag << offset--; | ||
558 | msg |= info.right_view_self_contained_flag << offset--; | ||
559 | |||
560 | addr[*size] = msg; | ||
561 | *size += 1; | ||
562 | |||
563 | addr[*size] = 0x80; | ||
564 | *size += 1; | ||
565 | |||
566 | return 0; | ||
567 | case SEI_BUFFERING_PERIOD: | ||
568 | case SEI_PICTURE_TIMING: | ||
569 | case SEI_FRAME_PACKING_ARRANGEMENT: | ||
570 | default: | ||
571 | dev_err(dev, "%s sei nal type not supported %d\n", | ||
572 | pctx->name, type); | ||
573 | return -EINVAL; | ||
574 | } | ||
575 | } | ||
576 | |||
577 | static int hva_h264_prepare_task(struct hva_ctx *pctx, | ||
578 | struct hva_h264_task *task, | ||
579 | struct hva_frame *frame, | ||
580 | struct hva_stream *stream) | ||
581 | { | ||
582 | struct hva_dev *hva = ctx_to_hdev(pctx); | ||
583 | struct device *dev = ctx_to_dev(pctx); | ||
584 | struct hva_h264_ctx *ctx = (struct hva_h264_ctx *)pctx->priv; | ||
585 | struct hva_buffer *seq_info = ctx->seq_info; | ||
586 | struct hva_buffer *fwd_ref_frame = ctx->ref_frame; | ||
587 | struct hva_buffer *loc_rec_frame = ctx->rec_frame; | ||
588 | struct hva_h264_td *td = &task->td; | ||
589 | struct hva_controls *ctrls = &pctx->ctrls; | ||
590 | struct v4l2_fract *time_per_frame = &pctx->ctrls.time_per_frame; | ||
591 | int cavlc = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC; | ||
592 | u32 frame_num = pctx->stream_num; | ||
593 | u32 addr_esram = hva->esram_addr; | ||
594 | enum v4l2_mpeg_video_h264_level level; | ||
595 | dma_addr_t paddr = 0; | ||
596 | u8 *slice_header_vaddr; | ||
597 | u32 frame_width = frame->info.aligned_width; | ||
598 | u32 frame_height = frame->info.aligned_height; | ||
599 | u32 max_cpb_buffer_size; | ||
600 | unsigned int payload = stream->bytesused; | ||
601 | u32 max_bitrate; | ||
602 | |||
603 | /* check width and height parameters */ | ||
604 | if ((frame_width > max(H264_MAX_SIZE_W, H264_MAX_SIZE_H)) || | ||
605 | (frame_height > max(H264_MAX_SIZE_W, H264_MAX_SIZE_H))) { | ||
606 | dev_err(dev, | ||
607 | "%s width(%d) or height(%d) exceeds limits (%dx%d)\n", | ||
608 | pctx->name, frame_width, frame_height, | ||
609 | H264_MAX_SIZE_W, H264_MAX_SIZE_H); | ||
610 | return -EINVAL; | ||
611 | } | ||
612 | |||
613 | level = ctrls->level; | ||
614 | |||
615 | memset(td, 0, sizeof(struct hva_h264_td)); | ||
616 | |||
617 | td->frame_width = frame_width; | ||
618 | td->frame_height = frame_height; | ||
619 | |||
620 | /* set frame alignement */ | ||
621 | td->window_width = frame_width; | ||
622 | td->window_height = frame_height; | ||
623 | td->window_horizontal_offset = 0; | ||
624 | td->window_vertical_offset = 0; | ||
625 | |||
626 | td->first_picture_in_sequence = (!frame_num) ? 1 : 0; | ||
627 | |||
628 | /* pic_order_cnt_type hard coded to '2' as only I & P frames */ | ||
629 | td->pic_order_cnt_type = 2; | ||
630 | |||
631 | /* useConstrainedIntraFlag set to false for better coding efficiency */ | ||
632 | td->use_constrained_intra_flag = false; | ||
633 | td->brc_type = (ctrls->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | ||
634 | ? BRC_TYPE_CBR : BRC_TYPE_VBR; | ||
635 | |||
636 | td->entropy_coding_mode = (ctrls->entropy_mode == cavlc) ? CAVLC : | ||
637 | CABAC; | ||
638 | |||
639 | td->bit_rate = ctrls->bitrate; | ||
640 | |||
641 | /* set framerate, framerate = 1 n/ time per frame */ | ||
642 | if (time_per_frame->numerator >= 536) { | ||
643 | /* | ||
644 | * due to a hardware bug, framerate denominator can't exceed | ||
645 | * 536 (BRC overflow). Compute nearest framerate | ||
646 | */ | ||
647 | td->framerate_den = 1; | ||
648 | td->framerate_num = (time_per_frame->denominator + | ||
649 | (time_per_frame->numerator >> 1) - 1) / | ||
650 | time_per_frame->numerator; | ||
651 | |||
652 | /* | ||
653 | * update bitrate to introduce a correction due to | ||
654 | * the new framerate | ||
655 | * new bitrate = (old bitrate * new framerate) / old framerate | ||
656 | */ | ||
657 | td->bit_rate /= time_per_frame->numerator; | ||
658 | td->bit_rate *= time_per_frame->denominator; | ||
659 | td->bit_rate /= td->framerate_num; | ||
660 | } else { | ||
661 | td->framerate_den = time_per_frame->numerator; | ||
662 | td->framerate_num = time_per_frame->denominator; | ||
663 | } | ||
664 | |||
665 | /* compute maximum bitrate depending on profile */ | ||
666 | if (ctrls->profile >= V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | ||
667 | max_bitrate = h264_infos_list[level].max_bitrate * | ||
668 | H264_FACTOR_HIGH; | ||
669 | else | ||
670 | max_bitrate = h264_infos_list[level].max_bitrate * | ||
671 | H264_FACTOR_BASELINE; | ||
672 | |||
673 | /* check if bitrate doesn't exceed max size */ | ||
674 | if (td->bit_rate > max_bitrate) { | ||
675 | dev_dbg(dev, | ||
676 | "%s bitrate (%d) larger than level and profile allow, clip to %d\n", | ||
677 | pctx->name, td->bit_rate, max_bitrate); | ||
678 | td->bit_rate = max_bitrate; | ||
679 | } | ||
680 | |||
681 | /* convert cpb_buffer_size in bits */ | ||
682 | td->cpb_buffer_size = ctrls->cpb_size * 8000; | ||
683 | |||
684 | /* compute maximum cpb buffer size depending on profile */ | ||
685 | if (ctrls->profile >= V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | ||
686 | max_cpb_buffer_size = | ||
687 | h264_infos_list[level].max_cpb_size * H264_FACTOR_HIGH; | ||
688 | else | ||
689 | max_cpb_buffer_size = | ||
690 | h264_infos_list[level].max_cpb_size * H264_FACTOR_BASELINE; | ||
691 | |||
692 | /* check if cpb buffer size doesn't exceed max size */ | ||
693 | if (td->cpb_buffer_size > max_cpb_buffer_size) { | ||
694 | dev_dbg(dev, | ||
695 | "%s cpb size larger than level %d allows, clip to %d\n", | ||
696 | pctx->name, td->cpb_buffer_size, max_cpb_buffer_size); | ||
697 | td->cpb_buffer_size = max_cpb_buffer_size; | ||
698 | } | ||
699 | |||
700 | /* enable skipping in the Bitrate Controller */ | ||
701 | td->brc_no_skip = 0; | ||
702 | |||
703 | /* initial delay */ | ||
704 | if ((ctrls->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) && | ||
705 | td->bit_rate) | ||
706 | td->delay = 1000 * (td->cpb_buffer_size / td->bit_rate); | ||
707 | else | ||
708 | td->delay = 0; | ||
709 | |||
710 | switch (frame->info.pixelformat) { | ||
711 | case V4L2_PIX_FMT_NV12: | ||
712 | td->sampling_mode = SAMPLING_MODE_NV12; | ||
713 | break; | ||
714 | case V4L2_PIX_FMT_NV21: | ||
715 | td->sampling_mode = SAMPLING_MODE_NV21; | ||
716 | break; | ||
717 | default: | ||
718 | dev_err(dev, "%s invalid source pixel format\n", | ||
719 | pctx->name); | ||
720 | return -EINVAL; | ||
721 | } | ||
722 | |||
723 | /* | ||
724 | * fill matrix color converter (RGB to YUV) | ||
725 | * Y = 0,299 R + 0,587 G + 0,114 B | ||
726 | * Cb = -0,1687 R -0,3313 G + 0,5 B + 128 | ||
727 | * Cr = 0,5 R - 0,4187 G - 0,0813 B + 128 | ||
728 | */ | ||
729 | td->rgb2_yuv_y_coeff = 0x12031008; | ||
730 | td->rgb2_yuv_u_coeff = 0x800EF7FB; | ||
731 | td->rgb2_yuv_v_coeff = 0x80FEF40E; | ||
732 | |||
733 | /* enable/disable transform mode */ | ||
734 | td->transform_mode = ctrls->dct8x8; | ||
735 | |||
736 | /* encoder complexity fix to 2, ENCODE_I_16x16_I_NxN_P_16x16_P_WxH */ | ||
737 | td->encoder_complexity = 2; | ||
738 | |||
739 | /* quant fix to 28, default VBR value */ | ||
740 | td->quant = 28; | ||
741 | |||
742 | if (td->framerate_den == 0) { | ||
743 | dev_err(dev, "%s invalid framerate\n", pctx->name); | ||
744 | return -EINVAL; | ||
745 | } | ||
746 | |||
747 | /* if automatic framerate, deactivate bitrate controller */ | ||
748 | if (td->framerate_num == 0) | ||
749 | td->brc_type = 0; | ||
750 | |||
751 | /* compliancy fix to true */ | ||
752 | td->strict_hrd_compliancy = 1; | ||
753 | |||
754 | /* set minimum & maximum quantizers */ | ||
755 | td->qp_min = clamp_val(ctrls->qpmin, 0, 51); | ||
756 | td->qp_max = clamp_val(ctrls->qpmax, 0, 51); | ||
757 | |||
758 | td->addr_source_buffer = frame->paddr; | ||
759 | td->addr_fwd_ref_buffer = fwd_ref_frame->paddr; | ||
760 | td->addr_rec_buffer = loc_rec_frame->paddr; | ||
761 | |||
762 | td->addr_output_bitstream_end = (u32)stream->paddr + stream->size; | ||
763 | |||
764 | td->addr_output_bitstream_start = (u32)stream->paddr; | ||
765 | td->bitstream_offset = (((u32)stream->paddr & 0xF) << 3) & | ||
766 | BITSTREAM_OFFSET_MASK; | ||
767 | |||
768 | td->addr_param_out = (u32)ctx->task->paddr + | ||
769 | offsetof(struct hva_h264_task, po); | ||
770 | |||
771 | /* swap spatial and temporal context */ | ||
772 | if (frame_num % 2) { | ||
773 | paddr = seq_info->paddr; | ||
774 | td->addr_spatial_context = ALIGN(paddr, 0x100); | ||
775 | paddr = seq_info->paddr + DATA_SIZE(frame_width, | ||
776 | frame_height); | ||
777 | td->addr_temporal_context = ALIGN(paddr, 0x100); | ||
778 | } else { | ||
779 | paddr = seq_info->paddr; | ||
780 | td->addr_temporal_context = ALIGN(paddr, 0x100); | ||
781 | paddr = seq_info->paddr + DATA_SIZE(frame_width, | ||
782 | frame_height); | ||
783 | td->addr_spatial_context = ALIGN(paddr, 0x100); | ||
784 | } | ||
785 | |||
786 | paddr = seq_info->paddr + 2 * DATA_SIZE(frame_width, frame_height); | ||
787 | |||
788 | td->addr_brc_in_out_parameter = ALIGN(paddr, 0x100); | ||
789 | |||
790 | paddr = td->addr_brc_in_out_parameter + BRC_DATA_SIZE; | ||
791 | td->addr_slice_header = ALIGN(paddr, 0x100); | ||
792 | td->addr_external_sw = ALIGN(addr_esram, 0x100); | ||
793 | |||
794 | addr_esram += SEARCH_WINDOW_BUFFER_MAX_SIZE(frame_width); | ||
795 | td->addr_local_rec_buffer = ALIGN(addr_esram, 0x100); | ||
796 | |||
797 | addr_esram += LOCAL_RECONSTRUCTED_BUFFER_MAX_SIZE(frame_width); | ||
798 | td->addr_lctx = ALIGN(addr_esram, 0x100); | ||
799 | |||
800 | addr_esram += CTX_MB_BUFFER_MAX_SIZE(max(frame_width, frame_height)); | ||
801 | td->addr_cabac_context_buffer = ALIGN(addr_esram, 0x100); | ||
802 | |||
803 | if (!(frame_num % ctrls->gop_size)) { | ||
804 | td->picture_coding_type = PICTURE_CODING_TYPE_I; | ||
805 | stream->vbuf.flags |= V4L2_BUF_FLAG_KEYFRAME; | ||
806 | } else { | ||
807 | td->picture_coding_type = PICTURE_CODING_TYPE_P; | ||
808 | stream->vbuf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; | ||
809 | } | ||
810 | |||
811 | /* fill the slice header part */ | ||
812 | slice_header_vaddr = seq_info->vaddr + (td->addr_slice_header - | ||
813 | seq_info->paddr); | ||
814 | |||
815 | hva_h264_fill_slice_header(pctx, slice_header_vaddr, ctrls, frame_num, | ||
816 | &td->slice_header_size_in_bits, | ||
817 | &td->slice_header_offset0, | ||
818 | &td->slice_header_offset1, | ||
819 | &td->slice_header_offset2); | ||
820 | |||
821 | td->chroma_qp_index_offset = 2; | ||
822 | td->slice_synchro_enable = 0; | ||
823 | td->max_slice_number = 1; | ||
824 | |||
825 | /* | ||
826 | * check the sps/pps header size for key frame only | ||
827 | * sps/pps header was previously fill by libv4l | ||
828 | * during qbuf of stream buffer | ||
829 | */ | ||
830 | if ((stream->vbuf.flags == V4L2_BUF_FLAG_KEYFRAME) && | ||
831 | (payload > MAX_SPS_PPS_SIZE)) { | ||
832 | dev_err(dev, "%s invalid sps/pps size %d\n", pctx->name, | ||
833 | payload); | ||
834 | return -EINVAL; | ||
835 | } | ||
836 | |||
837 | if (stream->vbuf.flags != V4L2_BUF_FLAG_KEYFRAME) | ||
838 | payload = 0; | ||
839 | |||
840 | /* add SEI nal (video stereo info) */ | ||
841 | if (ctrls->sei_fp && hva_h264_fill_sei_nal(pctx, SEI_STEREO_VIDEO_INFO, | ||
842 | (u8 *)stream->vaddr, | ||
843 | &payload)) { | ||
844 | dev_err(dev, "%s fail to get SEI nal\n", pctx->name); | ||
845 | return -EINVAL; | ||
846 | } | ||
847 | |||
848 | /* fill size of non-VCL NAL units (SPS, PPS, filler and SEI) */ | ||
849 | td->non_vcl_nalu_size = payload * 8; | ||
850 | |||
851 | /* compute bitstream offset & new start address of bitstream */ | ||
852 | td->addr_output_bitstream_start += ((payload >> 4) << 4); | ||
853 | td->bitstream_offset += (payload - ((payload >> 4) << 4)) * 8; | ||
854 | |||
855 | stream->bytesused = payload; | ||
856 | |||
857 | return 0; | ||
858 | } | ||
859 | |||
860 | static unsigned int hva_h264_get_stream_size(struct hva_h264_task *task) | ||
861 | { | ||
862 | struct hva_h264_po *po = &task->po; | ||
863 | |||
864 | return po->bitstream_size; | ||
865 | } | ||
866 | |||
867 | static u32 hva_h264_get_stuffing_bytes(struct hva_h264_task *task) | ||
868 | { | ||
869 | struct hva_h264_po *po = &task->po; | ||
870 | |||
871 | return po->stuffing_bits >> 3; | ||
872 | } | ||
873 | |||
874 | static int hva_h264_open(struct hva_ctx *pctx) | ||
875 | { | ||
876 | struct device *dev = ctx_to_dev(pctx); | ||
877 | struct hva_h264_ctx *ctx; | ||
878 | struct hva_dev *hva = ctx_to_hdev(pctx); | ||
879 | u32 frame_width = pctx->frameinfo.aligned_width; | ||
880 | u32 frame_height = pctx->frameinfo.aligned_height; | ||
881 | u32 size; | ||
882 | int ret; | ||
883 | |||
884 | /* check esram size necessary to encode a frame */ | ||
885 | size = SEARCH_WINDOW_BUFFER_MAX_SIZE(frame_width) + | ||
886 | LOCAL_RECONSTRUCTED_BUFFER_MAX_SIZE(frame_width) + | ||
887 | CTX_MB_BUFFER_MAX_SIZE(max(frame_width, frame_height)) + | ||
888 | CABAC_CONTEXT_BUFFER_MAX_SIZE(frame_width); | ||
889 | |||
890 | if (hva->esram_size < size) { | ||
891 | dev_err(dev, "%s not enough esram (max:%d request:%d)\n", | ||
892 | pctx->name, hva->esram_size, size); | ||
893 | ret = -EINVAL; | ||
894 | goto err; | ||
895 | } | ||
896 | |||
897 | /* allocate context for codec */ | ||
898 | ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | ||
899 | if (!ctx) { | ||
900 | ret = -ENOMEM; | ||
901 | goto err; | ||
902 | } | ||
903 | |||
904 | /* allocate sequence info buffer */ | ||
905 | ret = hva_mem_alloc(pctx, | ||
906 | 2 * DATA_SIZE(frame_width, frame_height) + | ||
907 | SLICE_HEADER_SIZE + | ||
908 | BRC_DATA_SIZE, | ||
909 | "hva sequence info", | ||
910 | &ctx->seq_info); | ||
911 | if (ret) { | ||
912 | dev_err(dev, | ||
913 | "%s failed to allocate sequence info buffer\n", | ||
914 | pctx->name); | ||
915 | goto err_ctx; | ||
916 | } | ||
917 | |||
918 | /* allocate reference frame buffer */ | ||
919 | ret = hva_mem_alloc(pctx, | ||
920 | frame_width * frame_height * 3 / 2, | ||
921 | "hva reference frame", | ||
922 | &ctx->ref_frame); | ||
923 | if (ret) { | ||
924 | dev_err(dev, "%s failed to allocate reference frame buffer\n", | ||
925 | pctx->name); | ||
926 | goto err_seq_info; | ||
927 | } | ||
928 | |||
929 | /* allocate reconstructed frame buffer */ | ||
930 | ret = hva_mem_alloc(pctx, | ||
931 | frame_width * frame_height * 3 / 2, | ||
932 | "hva reconstructed frame", | ||
933 | &ctx->rec_frame); | ||
934 | if (ret) { | ||
935 | dev_err(dev, | ||
936 | "%s failed to allocate reconstructed frame buffer\n", | ||
937 | pctx->name); | ||
938 | goto err_ref_frame; | ||
939 | } | ||
940 | |||
941 | /* allocate task descriptor */ | ||
942 | ret = hva_mem_alloc(pctx, | ||
943 | sizeof(struct hva_h264_task), | ||
944 | "hva task descriptor", | ||
945 | &ctx->task); | ||
946 | if (ret) { | ||
947 | dev_err(dev, | ||
948 | "%s failed to allocate task descriptor\n", | ||
949 | pctx->name); | ||
950 | goto err_rec_frame; | ||
951 | } | ||
952 | |||
953 | pctx->priv = (void *)ctx; | ||
954 | |||
955 | return 0; | ||
956 | |||
957 | err_rec_frame: | ||
958 | hva_mem_free(pctx, ctx->rec_frame); | ||
959 | err_ref_frame: | ||
960 | hva_mem_free(pctx, ctx->ref_frame); | ||
961 | err_seq_info: | ||
962 | hva_mem_free(pctx, ctx->seq_info); | ||
963 | err_ctx: | ||
964 | devm_kfree(dev, ctx); | ||
965 | err: | ||
966 | return ret; | ||
967 | } | ||
968 | |||
969 | static int hva_h264_close(struct hva_ctx *pctx) | ||
970 | { | ||
971 | struct hva_h264_ctx *ctx = (struct hva_h264_ctx *)pctx->priv; | ||
972 | struct device *dev = ctx_to_dev(pctx); | ||
973 | |||
974 | if (ctx->seq_info) | ||
975 | hva_mem_free(pctx, ctx->seq_info); | ||
976 | |||
977 | if (ctx->ref_frame) | ||
978 | hva_mem_free(pctx, ctx->ref_frame); | ||
979 | |||
980 | if (ctx->rec_frame) | ||
981 | hva_mem_free(pctx, ctx->rec_frame); | ||
982 | |||
983 | if (ctx->task) | ||
984 | hva_mem_free(pctx, ctx->task); | ||
985 | |||
986 | devm_kfree(dev, ctx); | ||
987 | |||
988 | return 0; | ||
989 | } | ||
990 | |||
991 | static int hva_h264_encode(struct hva_ctx *pctx, struct hva_frame *frame, | ||
992 | struct hva_stream *stream) | ||
993 | { | ||
994 | struct hva_h264_ctx *ctx = (struct hva_h264_ctx *)pctx->priv; | ||
995 | struct hva_h264_task *task = (struct hva_h264_task *)ctx->task->vaddr; | ||
996 | struct hva_buffer *tmp_frame; | ||
997 | u32 stuffing_bytes = 0; | ||
998 | int ret = 0; | ||
999 | |||
1000 | ret = hva_h264_prepare_task(pctx, task, frame, stream); | ||
1001 | if (ret) | ||
1002 | goto err; | ||
1003 | |||
1004 | ret = hva_hw_execute_task(pctx, H264_ENC, ctx->task); | ||
1005 | if (ret) | ||
1006 | goto err; | ||
1007 | |||
1008 | pctx->stream_num++; | ||
1009 | stream->bytesused += hva_h264_get_stream_size(task); | ||
1010 | |||
1011 | stuffing_bytes = hva_h264_get_stuffing_bytes(task); | ||
1012 | |||
1013 | if (stuffing_bytes) | ||
1014 | hva_h264_fill_data_nal(pctx, stuffing_bytes, | ||
1015 | (u8 *)stream->vaddr, | ||
1016 | stream->size, | ||
1017 | &stream->bytesused); | ||
1018 | |||
1019 | /* switch reference & reconstructed frame */ | ||
1020 | tmp_frame = ctx->ref_frame; | ||
1021 | ctx->ref_frame = ctx->rec_frame; | ||
1022 | ctx->rec_frame = tmp_frame; | ||
1023 | |||
1024 | return 0; | ||
1025 | err: | ||
1026 | stream->bytesused = 0; | ||
1027 | return ret; | ||
1028 | } | ||
1029 | |||
1030 | const struct hva_enc nv12h264enc = { | ||
1031 | .name = "H264(NV12)", | ||
1032 | .pixelformat = V4L2_PIX_FMT_NV12, | ||
1033 | .streamformat = V4L2_PIX_FMT_H264, | ||
1034 | .max_width = H264_MAX_SIZE_W, | ||
1035 | .max_height = H264_MAX_SIZE_H, | ||
1036 | .open = hva_h264_open, | ||
1037 | .close = hva_h264_close, | ||
1038 | .encode = hva_h264_encode, | ||
1039 | }; | ||
1040 | |||
1041 | const struct hva_enc nv21h264enc = { | ||
1042 | .name = "H264(NV21)", | ||
1043 | .pixelformat = V4L2_PIX_FMT_NV21, | ||
1044 | .streamformat = V4L2_PIX_FMT_H264, | ||
1045 | .max_width = H264_MAX_SIZE_W, | ||
1046 | .max_height = H264_MAX_SIZE_H, | ||
1047 | .open = hva_h264_open, | ||
1048 | .close = hva_h264_close, | ||
1049 | .encode = hva_h264_encode, | ||
1050 | }; | ||
diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c new file mode 100644 index 000000000000..d341d4994528 --- /dev/null +++ b/drivers/media/platform/sti/hva/hva-hw.c | |||
@@ -0,0 +1,538 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2015 | ||
3 | * Authors: Yannick Fertre <yannick.fertre@st.com> | ||
4 | * Hugues Fruchet <hugues.fruchet@st.com> | ||
5 | * License terms: GNU General Public License (GPL), version 2 | ||
6 | */ | ||
7 | |||
8 | #include <linux/clk.h> | ||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/platform_device.h> | ||
11 | #include <linux/pm_runtime.h> | ||
12 | |||
13 | #include "hva.h" | ||
14 | #include "hva-hw.h" | ||
15 | |||
16 | /* HVA register offsets */ | ||
17 | #define HVA_HIF_REG_RST 0x0100U | ||
18 | #define HVA_HIF_REG_RST_ACK 0x0104U | ||
19 | #define HVA_HIF_REG_MIF_CFG 0x0108U | ||
20 | #define HVA_HIF_REG_HEC_MIF_CFG 0x010CU | ||
21 | #define HVA_HIF_REG_CFL 0x0110U | ||
22 | #define HVA_HIF_FIFO_CMD 0x0114U | ||
23 | #define HVA_HIF_FIFO_STS 0x0118U | ||
24 | #define HVA_HIF_REG_SFL 0x011CU | ||
25 | #define HVA_HIF_REG_IT_ACK 0x0120U | ||
26 | #define HVA_HIF_REG_ERR_IT_ACK 0x0124U | ||
27 | #define HVA_HIF_REG_LMI_ERR 0x0128U | ||
28 | #define HVA_HIF_REG_EMI_ERR 0x012CU | ||
29 | #define HVA_HIF_REG_HEC_MIF_ERR 0x0130U | ||
30 | #define HVA_HIF_REG_HEC_STS 0x0134U | ||
31 | #define HVA_HIF_REG_HVC_STS 0x0138U | ||
32 | #define HVA_HIF_REG_HJE_STS 0x013CU | ||
33 | #define HVA_HIF_REG_CNT 0x0140U | ||
34 | #define HVA_HIF_REG_HEC_CHKSYN_DIS 0x0144U | ||
35 | #define HVA_HIF_REG_CLK_GATING 0x0148U | ||
36 | #define HVA_HIF_REG_VERSION 0x014CU | ||
37 | #define HVA_HIF_REG_BSM 0x0150U | ||
38 | |||
39 | /* define value for version id register (HVA_HIF_REG_VERSION) */ | ||
40 | #define VERSION_ID_MASK 0x0000FFFF | ||
41 | |||
42 | /* define values for BSM register (HVA_HIF_REG_BSM) */ | ||
43 | #define BSM_CFG_VAL1 0x0003F000 | ||
44 | #define BSM_CFG_VAL2 0x003F0000 | ||
45 | |||
46 | /* define values for memory interface register (HVA_HIF_REG_MIF_CFG) */ | ||
47 | #define MIF_CFG_VAL1 0x04460446 | ||
48 | #define MIF_CFG_VAL2 0x04460806 | ||
49 | #define MIF_CFG_VAL3 0x00000000 | ||
50 | |||
51 | /* define value for HEC memory interface register (HVA_HIF_REG_MIF_CFG) */ | ||
52 | #define HEC_MIF_CFG_VAL 0x000000C4 | ||
53 | |||
54 | /* Bits definition for clock gating register (HVA_HIF_REG_CLK_GATING) */ | ||
55 | #define CLK_GATING_HVC BIT(0) | ||
56 | #define CLK_GATING_HEC BIT(1) | ||
57 | #define CLK_GATING_HJE BIT(2) | ||
58 | |||
59 | /* fix hva clock rate */ | ||
60 | #define CLK_RATE 300000000 | ||
61 | |||
62 | /* fix delay for pmruntime */ | ||
63 | #define AUTOSUSPEND_DELAY_MS 3 | ||
64 | |||
65 | /* | ||
66 | * hw encode error values | ||
67 | * NO_ERROR: Success, Task OK | ||
68 | * H264_BITSTREAM_OVERSIZE: VECH264 Bitstream size > bitstream buffer | ||
69 | * H264_FRAME_SKIPPED: VECH264 Frame skipped (refers to CPB Buffer Size) | ||
70 | * H264_SLICE_LIMIT_SIZE: VECH264 MB > slice limit size | ||
71 | * H264_MAX_SLICE_NUMBER: VECH264 max slice number reached | ||
72 | * H264_SLICE_READY: VECH264 Slice ready | ||
73 | * TASK_LIST_FULL: HVA/FPC task list full | ||
74 | (discard latest transform command) | ||
75 | * UNKNOWN_COMMAND: Transform command not known by HVA/FPC | ||
76 | * WRONG_CODEC_OR_RESOLUTION: Wrong Codec or Resolution Selection | ||
77 | * NO_INT_COMPLETION: Time-out on interrupt completion | ||
78 | * LMI_ERR: Local Memory Interface Error | ||
79 | * EMI_ERR: External Memory Interface Error | ||
80 | * HECMI_ERR: HEC Memory Interface Error | ||
81 | */ | ||
82 | enum hva_hw_error { | ||
83 | NO_ERROR = 0x0, | ||
84 | H264_BITSTREAM_OVERSIZE = 0x2, | ||
85 | H264_FRAME_SKIPPED = 0x4, | ||
86 | H264_SLICE_LIMIT_SIZE = 0x5, | ||
87 | H264_MAX_SLICE_NUMBER = 0x7, | ||
88 | H264_SLICE_READY = 0x8, | ||
89 | TASK_LIST_FULL = 0xF0, | ||
90 | UNKNOWN_COMMAND = 0xF1, | ||
91 | WRONG_CODEC_OR_RESOLUTION = 0xF4, | ||
92 | NO_INT_COMPLETION = 0x100, | ||
93 | LMI_ERR = 0x101, | ||
94 | EMI_ERR = 0x102, | ||
95 | HECMI_ERR = 0x103, | ||
96 | }; | ||
97 | |||
98 | static irqreturn_t hva_hw_its_interrupt(int irq, void *data) | ||
99 | { | ||
100 | struct hva_dev *hva = data; | ||
101 | |||
102 | /* read status registers */ | ||
103 | hva->sts_reg = readl_relaxed(hva->regs + HVA_HIF_FIFO_STS); | ||
104 | hva->sfl_reg = readl_relaxed(hva->regs + HVA_HIF_REG_SFL); | ||
105 | |||
106 | /* acknowledge interruption */ | ||
107 | writel_relaxed(0x1, hva->regs + HVA_HIF_REG_IT_ACK); | ||
108 | |||
109 | return IRQ_WAKE_THREAD; | ||
110 | } | ||
111 | |||
112 | static irqreturn_t hva_hw_its_irq_thread(int irq, void *arg) | ||
113 | { | ||
114 | struct hva_dev *hva = arg; | ||
115 | struct device *dev = hva_to_dev(hva); | ||
116 | u32 status = hva->sts_reg & 0xFF; | ||
117 | u8 ctx_id = 0; | ||
118 | struct hva_ctx *ctx = NULL; | ||
119 | |||
120 | dev_dbg(dev, "%s %s: status: 0x%02x fifo level: 0x%02x\n", | ||
121 | HVA_PREFIX, __func__, hva->sts_reg & 0xFF, hva->sfl_reg & 0xF); | ||
122 | |||
123 | /* | ||
124 | * status: task_id[31:16] client_id[15:8] status[7:0] | ||
125 | * the context identifier is retrieved from the client identifier | ||
126 | */ | ||
127 | ctx_id = (hva->sts_reg & 0xFF00) >> 8; | ||
128 | if (ctx_id >= HVA_MAX_INSTANCES) { | ||
129 | dev_err(dev, "%s %s: bad context identifier: %d\n", | ||
130 | ctx->name, __func__, ctx_id); | ||
131 | ctx->hw_err = true; | ||
132 | goto out; | ||
133 | } | ||
134 | |||
135 | ctx = hva->instances[ctx_id]; | ||
136 | if (!ctx) | ||
137 | goto out; | ||
138 | |||
139 | switch (status) { | ||
140 | case NO_ERROR: | ||
141 | dev_dbg(dev, "%s %s: no error\n", | ||
142 | ctx->name, __func__); | ||
143 | ctx->hw_err = false; | ||
144 | break; | ||
145 | case H264_SLICE_READY: | ||
146 | dev_dbg(dev, "%s %s: h264 slice ready\n", | ||
147 | ctx->name, __func__); | ||
148 | ctx->hw_err = false; | ||
149 | break; | ||
150 | case H264_FRAME_SKIPPED: | ||
151 | dev_dbg(dev, "%s %s: h264 frame skipped\n", | ||
152 | ctx->name, __func__); | ||
153 | ctx->hw_err = false; | ||
154 | break; | ||
155 | case H264_BITSTREAM_OVERSIZE: | ||
156 | dev_err(dev, "%s %s:h264 bitstream oversize\n", | ||
157 | ctx->name, __func__); | ||
158 | ctx->hw_err = true; | ||
159 | break; | ||
160 | case H264_SLICE_LIMIT_SIZE: | ||
161 | dev_err(dev, "%s %s: h264 slice limit size is reached\n", | ||
162 | ctx->name, __func__); | ||
163 | ctx->hw_err = true; | ||
164 | break; | ||
165 | case H264_MAX_SLICE_NUMBER: | ||
166 | dev_err(dev, "%s %s: h264 max slice number is reached\n", | ||
167 | ctx->name, __func__); | ||
168 | ctx->hw_err = true; | ||
169 | break; | ||
170 | case TASK_LIST_FULL: | ||
171 | dev_err(dev, "%s %s:task list full\n", | ||
172 | ctx->name, __func__); | ||
173 | ctx->hw_err = true; | ||
174 | break; | ||
175 | case UNKNOWN_COMMAND: | ||
176 | dev_err(dev, "%s %s: command not known\n", | ||
177 | ctx->name, __func__); | ||
178 | ctx->hw_err = true; | ||
179 | break; | ||
180 | case WRONG_CODEC_OR_RESOLUTION: | ||
181 | dev_err(dev, "%s %s: wrong codec or resolution\n", | ||
182 | ctx->name, __func__); | ||
183 | ctx->hw_err = true; | ||
184 | break; | ||
185 | default: | ||
186 | dev_err(dev, "%s %s: status not recognized\n", | ||
187 | ctx->name, __func__); | ||
188 | ctx->hw_err = true; | ||
189 | break; | ||
190 | } | ||
191 | out: | ||
192 | complete(&hva->interrupt); | ||
193 | |||
194 | return IRQ_HANDLED; | ||
195 | } | ||
196 | |||
197 | static irqreturn_t hva_hw_err_interrupt(int irq, void *data) | ||
198 | { | ||
199 | struct hva_dev *hva = data; | ||
200 | |||
201 | /* read status registers */ | ||
202 | hva->sts_reg = readl_relaxed(hva->regs + HVA_HIF_FIFO_STS); | ||
203 | hva->sfl_reg = readl_relaxed(hva->regs + HVA_HIF_REG_SFL); | ||
204 | |||
205 | /* read error registers */ | ||
206 | hva->lmi_err_reg = readl_relaxed(hva->regs + HVA_HIF_REG_LMI_ERR); | ||
207 | hva->emi_err_reg = readl_relaxed(hva->regs + HVA_HIF_REG_EMI_ERR); | ||
208 | hva->hec_mif_err_reg = readl_relaxed(hva->regs + | ||
209 | HVA_HIF_REG_HEC_MIF_ERR); | ||
210 | |||
211 | /* acknowledge interruption */ | ||
212 | writel_relaxed(0x1, hva->regs + HVA_HIF_REG_IT_ACK); | ||
213 | |||
214 | return IRQ_WAKE_THREAD; | ||
215 | } | ||
216 | |||
217 | static irqreturn_t hva_hw_err_irq_thread(int irq, void *arg) | ||
218 | { | ||
219 | struct hva_dev *hva = arg; | ||
220 | struct device *dev = hva_to_dev(hva); | ||
221 | u8 ctx_id = 0; | ||
222 | struct hva_ctx *ctx; | ||
223 | |||
224 | dev_dbg(dev, "%s status: 0x%02x fifo level: 0x%02x\n", | ||
225 | HVA_PREFIX, hva->sts_reg & 0xFF, hva->sfl_reg & 0xF); | ||
226 | |||
227 | /* | ||
228 | * status: task_id[31:16] client_id[15:8] status[7:0] | ||
229 | * the context identifier is retrieved from the client identifier | ||
230 | */ | ||
231 | ctx_id = (hva->sts_reg & 0xFF00) >> 8; | ||
232 | if (ctx_id >= HVA_MAX_INSTANCES) { | ||
233 | dev_err(dev, "%s bad context identifier: %d\n", HVA_PREFIX, | ||
234 | ctx_id); | ||
235 | goto out; | ||
236 | } | ||
237 | |||
238 | ctx = hva->instances[ctx_id]; | ||
239 | if (!ctx) | ||
240 | goto out; | ||
241 | |||
242 | if (hva->lmi_err_reg) { | ||
243 | dev_err(dev, "%s local memory interface error: 0x%08x\n", | ||
244 | ctx->name, hva->lmi_err_reg); | ||
245 | ctx->hw_err = true; | ||
246 | } | ||
247 | |||
248 | if (hva->lmi_err_reg) { | ||
249 | dev_err(dev, "%s external memory interface error: 0x%08x\n", | ||
250 | ctx->name, hva->emi_err_reg); | ||
251 | ctx->hw_err = true; | ||
252 | } | ||
253 | |||
254 | if (hva->hec_mif_err_reg) { | ||
255 | dev_err(dev, "%s hec memory interface error: 0x%08x\n", | ||
256 | ctx->name, hva->hec_mif_err_reg); | ||
257 | ctx->hw_err = true; | ||
258 | } | ||
259 | out: | ||
260 | complete(&hva->interrupt); | ||
261 | |||
262 | return IRQ_HANDLED; | ||
263 | } | ||
264 | |||
265 | static unsigned long int hva_hw_get_ip_version(struct hva_dev *hva) | ||
266 | { | ||
267 | struct device *dev = hva_to_dev(hva); | ||
268 | unsigned long int version; | ||
269 | |||
270 | if (pm_runtime_get_sync(dev) < 0) { | ||
271 | dev_err(dev, "%s failed to get pm_runtime\n", HVA_PREFIX); | ||
272 | mutex_unlock(&hva->protect_mutex); | ||
273 | return -EFAULT; | ||
274 | } | ||
275 | |||
276 | version = readl_relaxed(hva->regs + HVA_HIF_REG_VERSION) & | ||
277 | VERSION_ID_MASK; | ||
278 | |||
279 | pm_runtime_put_autosuspend(dev); | ||
280 | |||
281 | switch (version) { | ||
282 | case HVA_VERSION_V400: | ||
283 | dev_dbg(dev, "%s IP hardware version 0x%lx\n", | ||
284 | HVA_PREFIX, version); | ||
285 | break; | ||
286 | default: | ||
287 | dev_err(dev, "%s unknown IP hardware version 0x%lx\n", | ||
288 | HVA_PREFIX, version); | ||
289 | version = HVA_VERSION_UNKNOWN; | ||
290 | break; | ||
291 | } | ||
292 | |||
293 | return version; | ||
294 | } | ||
295 | |||
296 | int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva) | ||
297 | { | ||
298 | struct device *dev = &pdev->dev; | ||
299 | struct resource *regs; | ||
300 | struct resource *esram; | ||
301 | int ret; | ||
302 | |||
303 | WARN_ON(!hva); | ||
304 | |||
305 | /* get memory for registers */ | ||
306 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
307 | hva->regs = devm_ioremap_resource(dev, regs); | ||
308 | if (IS_ERR_OR_NULL(hva->regs)) { | ||
309 | dev_err(dev, "%s failed to get regs\n", HVA_PREFIX); | ||
310 | return PTR_ERR(hva->regs); | ||
311 | } | ||
312 | |||
313 | /* get memory for esram */ | ||
314 | esram = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
315 | if (IS_ERR_OR_NULL(esram)) { | ||
316 | dev_err(dev, "%s failed to get esram\n", HVA_PREFIX); | ||
317 | return PTR_ERR(esram); | ||
318 | } | ||
319 | hva->esram_addr = esram->start; | ||
320 | hva->esram_size = resource_size(esram); | ||
321 | |||
322 | dev_info(dev, "%s esram reserved for address: 0x%x size:%d\n", | ||
323 | HVA_PREFIX, hva->esram_addr, hva->esram_size); | ||
324 | |||
325 | /* get clock resource */ | ||
326 | hva->clk = devm_clk_get(dev, "clk_hva"); | ||
327 | if (IS_ERR(hva->clk)) { | ||
328 | dev_err(dev, "%s failed to get clock\n", HVA_PREFIX); | ||
329 | return PTR_ERR(hva->clk); | ||
330 | } | ||
331 | |||
332 | ret = clk_prepare(hva->clk); | ||
333 | if (ret < 0) { | ||
334 | dev_err(dev, "%s failed to prepare clock\n", HVA_PREFIX); | ||
335 | hva->clk = ERR_PTR(-EINVAL); | ||
336 | return ret; | ||
337 | } | ||
338 | |||
339 | /* get status interruption resource */ | ||
340 | ret = platform_get_irq(pdev, 0); | ||
341 | if (ret < 0) { | ||
342 | dev_err(dev, "%s failed to get status IRQ\n", HVA_PREFIX); | ||
343 | goto err_clk; | ||
344 | } | ||
345 | hva->irq_its = ret; | ||
346 | |||
347 | ret = devm_request_threaded_irq(dev, hva->irq_its, hva_hw_its_interrupt, | ||
348 | hva_hw_its_irq_thread, | ||
349 | IRQF_ONESHOT, | ||
350 | "hva_its_irq", hva); | ||
351 | if (ret) { | ||
352 | dev_err(dev, "%s failed to install status IRQ 0x%x\n", | ||
353 | HVA_PREFIX, hva->irq_its); | ||
354 | goto err_clk; | ||
355 | } | ||
356 | disable_irq(hva->irq_its); | ||
357 | |||
358 | /* get error interruption resource */ | ||
359 | ret = platform_get_irq(pdev, 1); | ||
360 | if (ret < 0) { | ||
361 | dev_err(dev, "%s failed to get error IRQ\n", HVA_PREFIX); | ||
362 | goto err_clk; | ||
363 | } | ||
364 | hva->irq_err = ret; | ||
365 | |||
366 | ret = devm_request_threaded_irq(dev, hva->irq_err, hva_hw_err_interrupt, | ||
367 | hva_hw_err_irq_thread, | ||
368 | IRQF_ONESHOT, | ||
369 | "hva_err_irq", hva); | ||
370 | if (ret) { | ||
371 | dev_err(dev, "%s failed to install error IRQ 0x%x\n", | ||
372 | HVA_PREFIX, hva->irq_err); | ||
373 | goto err_clk; | ||
374 | } | ||
375 | disable_irq(hva->irq_err); | ||
376 | |||
377 | /* initialise protection mutex */ | ||
378 | mutex_init(&hva->protect_mutex); | ||
379 | |||
380 | /* initialise completion signal */ | ||
381 | init_completion(&hva->interrupt); | ||
382 | |||
383 | /* initialise runtime power management */ | ||
384 | pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_DELAY_MS); | ||
385 | pm_runtime_use_autosuspend(dev); | ||
386 | pm_runtime_set_suspended(dev); | ||
387 | pm_runtime_enable(dev); | ||
388 | |||
389 | ret = pm_runtime_get_sync(dev); | ||
390 | if (ret < 0) { | ||
391 | dev_err(dev, "%s failed to set PM\n", HVA_PREFIX); | ||
392 | goto err_clk; | ||
393 | } | ||
394 | |||
395 | /* check IP hardware version */ | ||
396 | hva->ip_version = hva_hw_get_ip_version(hva); | ||
397 | |||
398 | if (hva->ip_version == HVA_VERSION_UNKNOWN) { | ||
399 | ret = -EINVAL; | ||
400 | goto err_pm; | ||
401 | } | ||
402 | |||
403 | dev_info(dev, "%s found hva device (version 0x%lx)\n", HVA_PREFIX, | ||
404 | hva->ip_version); | ||
405 | |||
406 | return 0; | ||
407 | |||
408 | err_pm: | ||
409 | pm_runtime_put(dev); | ||
410 | err_clk: | ||
411 | if (hva->clk) | ||
412 | clk_unprepare(hva->clk); | ||
413 | |||
414 | return ret; | ||
415 | } | ||
416 | |||
417 | void hva_hw_remove(struct hva_dev *hva) | ||
418 | { | ||
419 | struct device *dev = hva_to_dev(hva); | ||
420 | |||
421 | disable_irq(hva->irq_its); | ||
422 | disable_irq(hva->irq_err); | ||
423 | |||
424 | pm_runtime_put_autosuspend(dev); | ||
425 | pm_runtime_disable(dev); | ||
426 | } | ||
427 | |||
428 | int hva_hw_runtime_suspend(struct device *dev) | ||
429 | { | ||
430 | struct hva_dev *hva = dev_get_drvdata(dev); | ||
431 | |||
432 | clk_disable_unprepare(hva->clk); | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | int hva_hw_runtime_resume(struct device *dev) | ||
438 | { | ||
439 | struct hva_dev *hva = dev_get_drvdata(dev); | ||
440 | |||
441 | if (clk_prepare_enable(hva->clk)) { | ||
442 | dev_err(hva->dev, "%s failed to prepare hva clk\n", | ||
443 | HVA_PREFIX); | ||
444 | return -EINVAL; | ||
445 | } | ||
446 | |||
447 | if (clk_set_rate(hva->clk, CLK_RATE)) { | ||
448 | dev_err(dev, "%s failed to set clock frequency\n", | ||
449 | HVA_PREFIX); | ||
450 | return -EINVAL; | ||
451 | } | ||
452 | |||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd, | ||
457 | struct hva_buffer *task) | ||
458 | { | ||
459 | struct hva_dev *hva = ctx_to_hdev(ctx); | ||
460 | struct device *dev = hva_to_dev(hva); | ||
461 | u8 client_id = ctx->id; | ||
462 | int ret; | ||
463 | u32 reg = 0; | ||
464 | |||
465 | mutex_lock(&hva->protect_mutex); | ||
466 | |||
467 | /* enable irqs */ | ||
468 | enable_irq(hva->irq_its); | ||
469 | enable_irq(hva->irq_err); | ||
470 | |||
471 | if (pm_runtime_get_sync(dev) < 0) { | ||
472 | dev_err(dev, "%s failed to get pm_runtime\n", ctx->name); | ||
473 | ret = -EFAULT; | ||
474 | goto out; | ||
475 | } | ||
476 | |||
477 | reg = readl_relaxed(hva->regs + HVA_HIF_REG_CLK_GATING); | ||
478 | switch (cmd) { | ||
479 | case H264_ENC: | ||
480 | reg |= CLK_GATING_HVC; | ||
481 | break; | ||
482 | default: | ||
483 | dev_dbg(dev, "%s unknown command 0x%x\n", ctx->name, cmd); | ||
484 | ret = -EFAULT; | ||
485 | goto out; | ||
486 | } | ||
487 | writel_relaxed(reg, hva->regs + HVA_HIF_REG_CLK_GATING); | ||
488 | |||
489 | dev_dbg(dev, "%s %s: write configuration registers\n", ctx->name, | ||
490 | __func__); | ||
491 | |||
492 | /* byte swap config */ | ||
493 | writel_relaxed(BSM_CFG_VAL1, hva->regs + HVA_HIF_REG_BSM); | ||
494 | |||
495 | /* define Max Opcode Size and Max Message Size for LMI and EMI */ | ||
496 | writel_relaxed(MIF_CFG_VAL3, hva->regs + HVA_HIF_REG_MIF_CFG); | ||
497 | writel_relaxed(HEC_MIF_CFG_VAL, hva->regs + HVA_HIF_REG_HEC_MIF_CFG); | ||
498 | |||
499 | /* | ||
500 | * command FIFO: task_id[31:16] client_id[15:8] command_type[7:0] | ||
501 | * the context identifier is provided as client identifier to the | ||
502 | * hardware, and is retrieved in the interrupt functions from the | ||
503 | * status register | ||
504 | */ | ||
505 | dev_dbg(dev, "%s %s: send task (cmd: %d, task_desc: %pad)\n", | ||
506 | ctx->name, __func__, cmd + (client_id << 8), &task->paddr); | ||
507 | writel_relaxed(cmd + (client_id << 8), hva->regs + HVA_HIF_FIFO_CMD); | ||
508 | writel_relaxed(task->paddr, hva->regs + HVA_HIF_FIFO_CMD); | ||
509 | |||
510 | if (!wait_for_completion_timeout(&hva->interrupt, | ||
511 | msecs_to_jiffies(2000))) { | ||
512 | dev_err(dev, "%s %s: time out on completion\n", ctx->name, | ||
513 | __func__); | ||
514 | ret = -EFAULT; | ||
515 | goto out; | ||
516 | } | ||
517 | |||
518 | /* get encoding status */ | ||
519 | ret = ctx->hw_err ? -EFAULT : 0; | ||
520 | |||
521 | out: | ||
522 | disable_irq(hva->irq_its); | ||
523 | disable_irq(hva->irq_err); | ||
524 | |||
525 | switch (cmd) { | ||
526 | case H264_ENC: | ||
527 | reg &= ~CLK_GATING_HVC; | ||
528 | writel_relaxed(reg, hva->regs + HVA_HIF_REG_CLK_GATING); | ||
529 | break; | ||
530 | default: | ||
531 | dev_dbg(dev, "%s unknown command 0x%x\n", ctx->name, cmd); | ||
532 | } | ||
533 | |||
534 | pm_runtime_put_autosuspend(dev); | ||
535 | mutex_unlock(&hva->protect_mutex); | ||
536 | |||
537 | return ret; | ||
538 | } | ||
diff --git a/drivers/media/platform/sti/hva/hva-hw.h b/drivers/media/platform/sti/hva/hva-hw.h new file mode 100644 index 000000000000..efb45b927524 --- /dev/null +++ b/drivers/media/platform/sti/hva/hva-hw.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2015 | ||
3 | * Authors: Yannick Fertre <yannick.fertre@st.com> | ||
4 | * Hugues Fruchet <hugues.fruchet@st.com> | ||
5 | * License terms: GNU General Public License (GPL), version 2 | ||
6 | */ | ||
7 | |||
8 | #ifndef HVA_HW_H | ||
9 | #define HVA_HW_H | ||
10 | |||
11 | #include "hva-mem.h" | ||
12 | |||
13 | /* HVA Versions */ | ||
14 | #define HVA_VERSION_UNKNOWN 0x000 | ||
15 | #define HVA_VERSION_V400 0x400 | ||
16 | |||
17 | /* HVA command types */ | ||
18 | enum hva_hw_cmd_type { | ||
19 | /* RESERVED = 0x00 */ | ||
20 | /* RESERVED = 0x01 */ | ||
21 | H264_ENC = 0x02, | ||
22 | /* RESERVED = 0x03 */ | ||
23 | /* RESERVED = 0x04 */ | ||
24 | /* RESERVED = 0x05 */ | ||
25 | /* RESERVED = 0x06 */ | ||
26 | /* RESERVED = 0x07 */ | ||
27 | REMOVE_CLIENT = 0x08, | ||
28 | FREEZE_CLIENT = 0x09, | ||
29 | START_CLIENT = 0x0A, | ||
30 | FREEZE_ALL = 0x0B, | ||
31 | START_ALL = 0x0C, | ||
32 | REMOVE_ALL = 0x0D | ||
33 | }; | ||
34 | |||
35 | int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva); | ||
36 | void hva_hw_remove(struct hva_dev *hva); | ||
37 | int hva_hw_runtime_suspend(struct device *dev); | ||
38 | int hva_hw_runtime_resume(struct device *dev); | ||
39 | int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd, | ||
40 | struct hva_buffer *task); | ||
41 | |||
42 | #endif /* HVA_HW_H */ | ||
diff --git a/drivers/media/platform/sti/hva/hva-mem.c b/drivers/media/platform/sti/hva/hva-mem.c new file mode 100644 index 000000000000..649f66007ad6 --- /dev/null +++ b/drivers/media/platform/sti/hva/hva-mem.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2015 | ||
3 | * Authors: Yannick Fertre <yannick.fertre@st.com> | ||
4 | * Hugues Fruchet <hugues.fruchet@st.com> | ||
5 | * License terms: GNU General Public License (GPL), version 2 | ||
6 | */ | ||
7 | |||
8 | #include "hva.h" | ||
9 | #include "hva-mem.h" | ||
10 | |||
11 | int hva_mem_alloc(struct hva_ctx *ctx, u32 size, const char *name, | ||
12 | struct hva_buffer **buf) | ||
13 | { | ||
14 | struct device *dev = ctx_to_dev(ctx); | ||
15 | struct hva_buffer *b; | ||
16 | dma_addr_t paddr; | ||
17 | void *base; | ||
18 | |||
19 | b = devm_kzalloc(dev, sizeof(*b), GFP_KERNEL); | ||
20 | if (!b) | ||
21 | return -ENOMEM; | ||
22 | |||
23 | base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL | GFP_DMA, | ||
24 | DMA_ATTR_WRITE_COMBINE); | ||
25 | if (!base) { | ||
26 | dev_err(dev, "%s %s : dma_alloc_attrs failed for %s (size=%d)\n", | ||
27 | ctx->name, __func__, name, size); | ||
28 | devm_kfree(dev, b); | ||
29 | return -ENOMEM; | ||
30 | } | ||
31 | |||
32 | b->size = size; | ||
33 | b->paddr = paddr; | ||
34 | b->vaddr = base; | ||
35 | b->name = name; | ||
36 | |||
37 | dev_dbg(dev, | ||
38 | "%s allocate %d bytes of HW memory @(virt=%p, phy=%pad): %s\n", | ||
39 | ctx->name, size, b->vaddr, &b->paddr, b->name); | ||
40 | |||
41 | /* return hva buffer to user */ | ||
42 | *buf = b; | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | void hva_mem_free(struct hva_ctx *ctx, struct hva_buffer *buf) | ||
48 | { | ||
49 | struct device *dev = ctx_to_dev(ctx); | ||
50 | |||
51 | dev_dbg(dev, | ||
52 | "%s free %d bytes of HW memory @(virt=%p, phy=%pad): %s\n", | ||
53 | ctx->name, buf->size, buf->vaddr, &buf->paddr, buf->name); | ||
54 | |||
55 | dma_free_attrs(dev, buf->size, buf->vaddr, buf->paddr, | ||
56 | DMA_ATTR_WRITE_COMBINE); | ||
57 | |||
58 | devm_kfree(dev, buf); | ||
59 | } | ||
diff --git a/drivers/media/platform/sti/hva/hva-mem.h b/drivers/media/platform/sti/hva/hva-mem.h new file mode 100644 index 000000000000..a95c728a45e6 --- /dev/null +++ b/drivers/media/platform/sti/hva/hva-mem.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2015 | ||
3 | * Authors: Yannick Fertre <yannick.fertre@st.com> | ||
4 | * Hugues Fruchet <hugues.fruchet@st.com> | ||
5 | * License terms: GNU General Public License (GPL), version 2 | ||
6 | */ | ||
7 | |||
8 | #ifndef HVA_MEM_H | ||
9 | #define HVA_MEM_H | ||
10 | |||
11 | /** | ||
12 | * struct hva_buffer - hva buffer | ||
13 | * | ||
14 | * @name: name of requester | ||
15 | * @paddr: physical address (for hardware) | ||
16 | * @vaddr: virtual address (kernel can read/write) | ||
17 | * @size: size of buffer | ||
18 | */ | ||
19 | struct hva_buffer { | ||
20 | const char *name; | ||
21 | dma_addr_t paddr; | ||
22 | void *vaddr; | ||
23 | u32 size; | ||
24 | }; | ||
25 | |||
26 | int hva_mem_alloc(struct hva_ctx *ctx, | ||
27 | __u32 size, | ||
28 | const char *name, | ||
29 | struct hva_buffer **buf); | ||
30 | |||
31 | void hva_mem_free(struct hva_ctx *ctx, | ||
32 | struct hva_buffer *buf); | ||
33 | |||
34 | #endif /* HVA_MEM_H */ | ||
diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c new file mode 100644 index 000000000000..6bf3c8588230 --- /dev/null +++ b/drivers/media/platform/sti/hva/hva-v4l2.c | |||
@@ -0,0 +1,1415 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2015 | ||
3 | * Authors: Yannick Fertre <yannick.fertre@st.com> | ||
4 | * Hugues Fruchet <hugues.fruchet@st.com> | ||
5 | * License terms: GNU General Public License (GPL), version 2 | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/platform_device.h> | ||
10 | #include <linux/slab.h> | ||
11 | #include <media/v4l2-event.h> | ||
12 | #include <media/v4l2-ioctl.h> | ||
13 | #include <media/videobuf2-dma-contig.h> | ||
14 | |||
15 | #include "hva.h" | ||
16 | #include "hva-hw.h" | ||
17 | |||
18 | #define HVA_NAME "st-hva" | ||
19 | |||
20 | #define MIN_FRAMES 1 | ||
21 | #define MIN_STREAMS 1 | ||
22 | |||
23 | #define HVA_MIN_WIDTH 32 | ||
24 | #define HVA_MAX_WIDTH 1920 | ||
25 | #define HVA_MIN_HEIGHT 32 | ||
26 | #define HVA_MAX_HEIGHT 1920 | ||
27 | |||
28 | /* HVA requires a 16x16 pixels alignment for frames */ | ||
29 | #define HVA_WIDTH_ALIGNMENT 16 | ||
30 | #define HVA_HEIGHT_ALIGNMENT 16 | ||
31 | |||
32 | #define HVA_DEFAULT_WIDTH HVA_MIN_WIDTH | ||
33 | #define HVA_DEFAULT_HEIGHT HVA_MIN_HEIGHT | ||
34 | #define HVA_DEFAULT_FRAME_NUM 1 | ||
35 | #define HVA_DEFAULT_FRAME_DEN 30 | ||
36 | |||
37 | #define to_type_str(type) (type == V4L2_BUF_TYPE_VIDEO_OUTPUT ? \ | ||
38 | "frame" : "stream") | ||
39 | |||
40 | #define fh_to_ctx(f) (container_of(f, struct hva_ctx, fh)) | ||
41 | |||
42 | /* registry of available encoders */ | ||
43 | static const struct hva_enc *hva_encoders[] = { | ||
44 | &nv12h264enc, | ||
45 | &nv21h264enc, | ||
46 | }; | ||
47 | |||
48 | static inline int frame_size(u32 w, u32 h, u32 fmt) | ||
49 | { | ||
50 | switch (fmt) { | ||
51 | case V4L2_PIX_FMT_NV12: | ||
52 | case V4L2_PIX_FMT_NV21: | ||
53 | return (w * h * 3) / 2; | ||
54 | default: | ||
55 | return 0; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | static inline int frame_stride(u32 w, u32 fmt) | ||
60 | { | ||
61 | switch (fmt) { | ||
62 | case V4L2_PIX_FMT_NV12: | ||
63 | case V4L2_PIX_FMT_NV21: | ||
64 | return w; | ||
65 | default: | ||
66 | return 0; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | static inline int frame_alignment(u32 fmt) | ||
71 | { | ||
72 | switch (fmt) { | ||
73 | case V4L2_PIX_FMT_NV12: | ||
74 | case V4L2_PIX_FMT_NV21: | ||
75 | /* multiple of 2 */ | ||
76 | return 2; | ||
77 | default: | ||
78 | return 1; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | static inline int estimated_stream_size(u32 w, u32 h) | ||
83 | { | ||
84 | /* | ||
85 | * HVA only encodes in YUV420 format, whatever the frame format. | ||
86 | * A compression ratio of 2 is assumed: thus, the maximum size | ||
87 | * of a stream is estimated to ((width x height x 3 / 2) / 2) | ||
88 | */ | ||
89 | return (w * h * 3) / 4; | ||
90 | } | ||
91 | |||
92 | static void set_default_params(struct hva_ctx *ctx) | ||
93 | { | ||
94 | struct hva_frameinfo *frameinfo = &ctx->frameinfo; | ||
95 | struct hva_streaminfo *streaminfo = &ctx->streaminfo; | ||
96 | |||
97 | frameinfo->pixelformat = V4L2_PIX_FMT_NV12; | ||
98 | frameinfo->width = HVA_DEFAULT_WIDTH; | ||
99 | frameinfo->height = HVA_DEFAULT_HEIGHT; | ||
100 | frameinfo->aligned_width = ALIGN(frameinfo->width, | ||
101 | HVA_WIDTH_ALIGNMENT); | ||
102 | frameinfo->aligned_height = ALIGN(frameinfo->height, | ||
103 | HVA_HEIGHT_ALIGNMENT); | ||
104 | frameinfo->size = frame_size(frameinfo->aligned_width, | ||
105 | frameinfo->aligned_height, | ||
106 | frameinfo->pixelformat); | ||
107 | |||
108 | streaminfo->streamformat = V4L2_PIX_FMT_H264; | ||
109 | streaminfo->width = HVA_DEFAULT_WIDTH; | ||
110 | streaminfo->height = HVA_DEFAULT_HEIGHT; | ||
111 | |||
112 | ctx->colorspace = V4L2_COLORSPACE_REC709; | ||
113 | ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; | ||
114 | ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | ||
115 | ctx->quantization = V4L2_QUANTIZATION_DEFAULT; | ||
116 | |||
117 | ctx->max_stream_size = estimated_stream_size(streaminfo->width, | ||
118 | streaminfo->height); | ||
119 | } | ||
120 | |||
121 | static const struct hva_enc *hva_find_encoder(struct hva_ctx *ctx, | ||
122 | u32 pixelformat, | ||
123 | u32 streamformat) | ||
124 | { | ||
125 | struct hva_dev *hva = ctx_to_hdev(ctx); | ||
126 | const struct hva_enc *enc; | ||
127 | unsigned int i; | ||
128 | |||
129 | for (i = 0; i < hva->nb_of_encoders; i++) { | ||
130 | enc = hva->encoders[i]; | ||
131 | if ((enc->pixelformat == pixelformat) && | ||
132 | (enc->streamformat == streamformat)) | ||
133 | return enc; | ||
134 | } | ||
135 | |||
136 | return NULL; | ||
137 | } | ||
138 | |||
139 | static void register_format(u32 format, u32 formats[], u32 *nb_of_formats) | ||
140 | { | ||
141 | u32 i; | ||
142 | bool found = false; | ||
143 | |||
144 | for (i = 0; i < *nb_of_formats; i++) { | ||
145 | if (format == formats[i]) { | ||
146 | found = true; | ||
147 | break; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | if (!found) | ||
152 | formats[(*nb_of_formats)++] = format; | ||
153 | } | ||
154 | |||
155 | static void register_formats(struct hva_dev *hva) | ||
156 | { | ||
157 | unsigned int i; | ||
158 | |||
159 | for (i = 0; i < hva->nb_of_encoders; i++) { | ||
160 | register_format(hva->encoders[i]->pixelformat, | ||
161 | hva->pixelformats, | ||
162 | &hva->nb_of_pixelformats); | ||
163 | |||
164 | register_format(hva->encoders[i]->streamformat, | ||
165 | hva->streamformats, | ||
166 | &hva->nb_of_streamformats); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | static void register_encoders(struct hva_dev *hva) | ||
171 | { | ||
172 | struct device *dev = hva_to_dev(hva); | ||
173 | unsigned int i; | ||
174 | |||
175 | for (i = 0; i < ARRAY_SIZE(hva_encoders); i++) { | ||
176 | if (hva->nb_of_encoders >= HVA_MAX_ENCODERS) { | ||
177 | dev_dbg(dev, | ||
178 | "%s failed to register %s encoder (%d maximum reached)\n", | ||
179 | HVA_PREFIX, hva_encoders[i]->name, | ||
180 | HVA_MAX_ENCODERS); | ||
181 | return; | ||
182 | } | ||
183 | |||
184 | hva->encoders[hva->nb_of_encoders++] = hva_encoders[i]; | ||
185 | dev_info(dev, "%s %s encoder registered\n", HVA_PREFIX, | ||
186 | hva_encoders[i]->name); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | static int hva_open_encoder(struct hva_ctx *ctx, u32 streamformat, | ||
191 | u32 pixelformat, struct hva_enc **penc) | ||
192 | { | ||
193 | struct hva_dev *hva = ctx_to_hdev(ctx); | ||
194 | struct device *dev = ctx_to_dev(ctx); | ||
195 | struct hva_enc *enc; | ||
196 | int ret; | ||
197 | |||
198 | /* find an encoder which can deal with these formats */ | ||
199 | enc = (struct hva_enc *)hva_find_encoder(ctx, pixelformat, | ||
200 | streamformat); | ||
201 | if (!enc) { | ||
202 | dev_err(dev, "%s no encoder found matching %4.4s => %4.4s\n", | ||
203 | ctx->name, (char *)&pixelformat, (char *)&streamformat); | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | |||
207 | dev_dbg(dev, "%s one encoder matching %4.4s => %4.4s\n", | ||
208 | ctx->name, (char *)&pixelformat, (char *)&streamformat); | ||
209 | |||
210 | /* update instance name */ | ||
211 | snprintf(ctx->name, sizeof(ctx->name), "[%3d:%4.4s]", | ||
212 | hva->instance_id, (char *)&streamformat); | ||
213 | |||
214 | /* open encoder instance */ | ||
215 | ret = enc->open(ctx); | ||
216 | if (ret) { | ||
217 | dev_err(dev, "%s failed to open encoder instance (%d)\n", | ||
218 | ctx->name, ret); | ||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | dev_dbg(dev, "%s %s encoder opened\n", ctx->name, enc->name); | ||
223 | |||
224 | *penc = enc; | ||
225 | |||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * V4L2 ioctl operations | ||
231 | */ | ||
232 | |||
233 | static int hva_querycap(struct file *file, void *priv, | ||
234 | struct v4l2_capability *cap) | ||
235 | { | ||
236 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
237 | struct hva_dev *hva = ctx_to_hdev(ctx); | ||
238 | |||
239 | strlcpy(cap->driver, HVA_NAME, sizeof(cap->driver)); | ||
240 | strlcpy(cap->card, hva->vdev->name, sizeof(cap->card)); | ||
241 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", | ||
242 | hva->pdev->name); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int hva_enum_fmt_stream(struct file *file, void *priv, | ||
248 | struct v4l2_fmtdesc *f) | ||
249 | { | ||
250 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
251 | struct hva_dev *hva = ctx_to_hdev(ctx); | ||
252 | |||
253 | if (unlikely(f->index >= hva->nb_of_streamformats)) | ||
254 | return -EINVAL; | ||
255 | |||
256 | f->pixelformat = hva->streamformats[f->index]; | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int hva_enum_fmt_frame(struct file *file, void *priv, | ||
262 | struct v4l2_fmtdesc *f) | ||
263 | { | ||
264 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
265 | struct hva_dev *hva = ctx_to_hdev(ctx); | ||
266 | |||
267 | if (unlikely(f->index >= hva->nb_of_pixelformats)) | ||
268 | return -EINVAL; | ||
269 | |||
270 | f->pixelformat = hva->pixelformats[f->index]; | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int hva_g_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) | ||
276 | { | ||
277 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
278 | struct hva_streaminfo *streaminfo = &ctx->streaminfo; | ||
279 | |||
280 | f->fmt.pix.width = streaminfo->width; | ||
281 | f->fmt.pix.height = streaminfo->height; | ||
282 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
283 | f->fmt.pix.colorspace = ctx->colorspace; | ||
284 | f->fmt.pix.xfer_func = ctx->xfer_func; | ||
285 | f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; | ||
286 | f->fmt.pix.quantization = ctx->quantization; | ||
287 | f->fmt.pix.pixelformat = streaminfo->streamformat; | ||
288 | f->fmt.pix.bytesperline = 0; | ||
289 | f->fmt.pix.sizeimage = ctx->max_stream_size; | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int hva_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) | ||
295 | { | ||
296 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
297 | struct hva_frameinfo *frameinfo = &ctx->frameinfo; | ||
298 | |||
299 | f->fmt.pix.width = frameinfo->width; | ||
300 | f->fmt.pix.height = frameinfo->height; | ||
301 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
302 | f->fmt.pix.colorspace = ctx->colorspace; | ||
303 | f->fmt.pix.xfer_func = ctx->xfer_func; | ||
304 | f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; | ||
305 | f->fmt.pix.quantization = ctx->quantization; | ||
306 | f->fmt.pix.pixelformat = frameinfo->pixelformat; | ||
307 | f->fmt.pix.bytesperline = frame_stride(frameinfo->aligned_width, | ||
308 | frameinfo->pixelformat); | ||
309 | f->fmt.pix.sizeimage = frameinfo->size; | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int hva_try_fmt_stream(struct file *file, void *priv, | ||
315 | struct v4l2_format *f) | ||
316 | { | ||
317 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
318 | struct device *dev = ctx_to_dev(ctx); | ||
319 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
320 | u32 streamformat = pix->pixelformat; | ||
321 | const struct hva_enc *enc; | ||
322 | u32 width, height; | ||
323 | u32 stream_size; | ||
324 | |||
325 | enc = hva_find_encoder(ctx, ctx->frameinfo.pixelformat, streamformat); | ||
326 | if (!enc) { | ||
327 | dev_dbg(dev, | ||
328 | "%s V4L2 TRY_FMT (CAPTURE): unsupported format %.4s\n", | ||
329 | ctx->name, (char *)&pix->pixelformat); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | |||
333 | width = pix->width; | ||
334 | height = pix->height; | ||
335 | if (ctx->flags & HVA_FLAG_FRAMEINFO) { | ||
336 | /* | ||
337 | * if the frame resolution is already fixed, only allow the | ||
338 | * same stream resolution | ||
339 | */ | ||
340 | pix->width = ctx->frameinfo.width; | ||
341 | pix->height = ctx->frameinfo.height; | ||
342 | if ((pix->width != width) || (pix->height != height)) | ||
343 | dev_dbg(dev, | ||
344 | "%s V4L2 TRY_FMT (CAPTURE): resolution updated %dx%d -> %dx%d to fit frame resolution\n", | ||
345 | ctx->name, width, height, | ||
346 | pix->width, pix->height); | ||
347 | } else { | ||
348 | /* adjust width & height */ | ||
349 | v4l_bound_align_image(&pix->width, | ||
350 | HVA_MIN_WIDTH, enc->max_width, | ||
351 | 0, | ||
352 | &pix->height, | ||
353 | HVA_MIN_HEIGHT, enc->max_height, | ||
354 | 0, | ||
355 | 0); | ||
356 | |||
357 | if ((pix->width != width) || (pix->height != height)) | ||
358 | dev_dbg(dev, | ||
359 | "%s V4L2 TRY_FMT (CAPTURE): resolution updated %dx%d -> %dx%d to fit min/max/alignment\n", | ||
360 | ctx->name, width, height, | ||
361 | pix->width, pix->height); | ||
362 | } | ||
363 | |||
364 | stream_size = estimated_stream_size(pix->width, pix->height); | ||
365 | if (pix->sizeimage < stream_size) | ||
366 | pix->sizeimage = stream_size; | ||
367 | |||
368 | pix->bytesperline = 0; | ||
369 | pix->colorspace = ctx->colorspace; | ||
370 | pix->xfer_func = ctx->xfer_func; | ||
371 | pix->ycbcr_enc = ctx->ycbcr_enc; | ||
372 | pix->quantization = ctx->quantization; | ||
373 | pix->field = V4L2_FIELD_NONE; | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int hva_try_fmt_frame(struct file *file, void *priv, | ||
379 | struct v4l2_format *f) | ||
380 | { | ||
381 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
382 | struct device *dev = ctx_to_dev(ctx); | ||
383 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
384 | u32 pixelformat = pix->pixelformat; | ||
385 | const struct hva_enc *enc; | ||
386 | u32 width, height; | ||
387 | |||
388 | enc = hva_find_encoder(ctx, pixelformat, ctx->streaminfo.streamformat); | ||
389 | if (!enc) { | ||
390 | dev_dbg(dev, | ||
391 | "%s V4L2 TRY_FMT (OUTPUT): unsupported format %.4s\n", | ||
392 | ctx->name, (char *)&pixelformat); | ||
393 | return -EINVAL; | ||
394 | } | ||
395 | |||
396 | /* adjust width & height */ | ||
397 | width = pix->width; | ||
398 | height = pix->height; | ||
399 | v4l_bound_align_image(&pix->width, | ||
400 | HVA_MIN_WIDTH, HVA_MAX_WIDTH, | ||
401 | frame_alignment(pixelformat) - 1, | ||
402 | &pix->height, | ||
403 | HVA_MIN_HEIGHT, HVA_MAX_HEIGHT, | ||
404 | frame_alignment(pixelformat) - 1, | ||
405 | 0); | ||
406 | |||
407 | if ((pix->width != width) || (pix->height != height)) | ||
408 | dev_dbg(dev, | ||
409 | "%s V4L2 TRY_FMT (OUTPUT): resolution updated %dx%d -> %dx%d to fit min/max/alignment\n", | ||
410 | ctx->name, width, height, pix->width, pix->height); | ||
411 | |||
412 | width = ALIGN(pix->width, HVA_WIDTH_ALIGNMENT); | ||
413 | height = ALIGN(pix->height, HVA_HEIGHT_ALIGNMENT); | ||
414 | |||
415 | if (!pix->colorspace) { | ||
416 | pix->colorspace = V4L2_COLORSPACE_REC709; | ||
417 | pix->xfer_func = V4L2_XFER_FUNC_DEFAULT; | ||
418 | pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | ||
419 | pix->quantization = V4L2_QUANTIZATION_DEFAULT; | ||
420 | } | ||
421 | |||
422 | pix->bytesperline = frame_stride(width, pixelformat); | ||
423 | pix->sizeimage = frame_size(width, height, pixelformat); | ||
424 | pix->field = V4L2_FIELD_NONE; | ||
425 | |||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | static int hva_s_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) | ||
430 | { | ||
431 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
432 | struct device *dev = ctx_to_dev(ctx); | ||
433 | struct vb2_queue *vq; | ||
434 | int ret; | ||
435 | |||
436 | ret = hva_try_fmt_stream(file, fh, f); | ||
437 | if (ret) { | ||
438 | dev_dbg(dev, "%s V4L2 S_FMT (CAPTURE): unsupported format %.4s\n", | ||
439 | ctx->name, (char *)&f->fmt.pix.pixelformat); | ||
440 | return ret; | ||
441 | } | ||
442 | |||
443 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); | ||
444 | if (vb2_is_streaming(vq)) { | ||
445 | dev_dbg(dev, "%s V4L2 S_FMT (CAPTURE): queue busy\n", | ||
446 | ctx->name); | ||
447 | return -EBUSY; | ||
448 | } | ||
449 | |||
450 | ctx->max_stream_size = f->fmt.pix.sizeimage; | ||
451 | ctx->streaminfo.width = f->fmt.pix.width; | ||
452 | ctx->streaminfo.height = f->fmt.pix.height; | ||
453 | ctx->streaminfo.streamformat = f->fmt.pix.pixelformat; | ||
454 | ctx->flags |= HVA_FLAG_STREAMINFO; | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static int hva_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) | ||
460 | { | ||
461 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
462 | struct device *dev = ctx_to_dev(ctx); | ||
463 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
464 | struct vb2_queue *vq; | ||
465 | int ret; | ||
466 | |||
467 | ret = hva_try_fmt_frame(file, fh, f); | ||
468 | if (ret) { | ||
469 | dev_dbg(dev, "%s V4L2 S_FMT (OUTPUT): unsupported format %.4s\n", | ||
470 | ctx->name, (char *)&pix->pixelformat); | ||
471 | return ret; | ||
472 | } | ||
473 | |||
474 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); | ||
475 | if (vb2_is_streaming(vq)) { | ||
476 | dev_dbg(dev, "%s V4L2 S_FMT (OUTPUT): queue busy\n", ctx->name); | ||
477 | return -EBUSY; | ||
478 | } | ||
479 | |||
480 | ctx->colorspace = pix->colorspace; | ||
481 | ctx->xfer_func = pix->xfer_func; | ||
482 | ctx->ycbcr_enc = pix->ycbcr_enc; | ||
483 | ctx->quantization = pix->quantization; | ||
484 | |||
485 | ctx->frameinfo.aligned_width = ALIGN(pix->width, HVA_WIDTH_ALIGNMENT); | ||
486 | ctx->frameinfo.aligned_height = ALIGN(pix->height, | ||
487 | HVA_HEIGHT_ALIGNMENT); | ||
488 | ctx->frameinfo.size = pix->sizeimage; | ||
489 | ctx->frameinfo.pixelformat = pix->pixelformat; | ||
490 | ctx->frameinfo.width = pix->width; | ||
491 | ctx->frameinfo.height = pix->height; | ||
492 | ctx->flags |= HVA_FLAG_FRAMEINFO; | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static int hva_g_parm(struct file *file, void *fh, struct v4l2_streamparm *sp) | ||
498 | { | ||
499 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
500 | struct v4l2_fract *time_per_frame = &ctx->ctrls.time_per_frame; | ||
501 | |||
502 | if (sp->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
503 | return -EINVAL; | ||
504 | |||
505 | sp->parm.output.capability = V4L2_CAP_TIMEPERFRAME; | ||
506 | sp->parm.output.timeperframe.numerator = time_per_frame->numerator; | ||
507 | sp->parm.output.timeperframe.denominator = | ||
508 | time_per_frame->denominator; | ||
509 | |||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static int hva_s_parm(struct file *file, void *fh, struct v4l2_streamparm *sp) | ||
514 | { | ||
515 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
516 | struct v4l2_fract *time_per_frame = &ctx->ctrls.time_per_frame; | ||
517 | |||
518 | if (sp->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
519 | return -EINVAL; | ||
520 | |||
521 | if (!sp->parm.output.timeperframe.numerator || | ||
522 | !sp->parm.output.timeperframe.denominator) | ||
523 | return hva_g_parm(file, fh, sp); | ||
524 | |||
525 | sp->parm.output.capability = V4L2_CAP_TIMEPERFRAME; | ||
526 | time_per_frame->numerator = sp->parm.output.timeperframe.numerator; | ||
527 | time_per_frame->denominator = | ||
528 | sp->parm.output.timeperframe.denominator; | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
534 | { | ||
535 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
536 | struct device *dev = ctx_to_dev(ctx); | ||
537 | |||
538 | if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
539 | /* | ||
540 | * depending on the targeted compressed video format, the | ||
541 | * capture buffer might contain headers (e.g. H.264 SPS/PPS) | ||
542 | * filled in by the driver client; the size of these data is | ||
543 | * copied from the bytesused field of the V4L2 buffer in the | ||
544 | * payload field of the hva stream buffer | ||
545 | */ | ||
546 | struct vb2_queue *vq; | ||
547 | struct hva_stream *stream; | ||
548 | |||
549 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, buf->type); | ||
550 | |||
551 | if (buf->index >= vq->num_buffers) { | ||
552 | dev_dbg(dev, "%s buffer index %d out of range (%d)\n", | ||
553 | ctx->name, buf->index, vq->num_buffers); | ||
554 | return -EINVAL; | ||
555 | } | ||
556 | |||
557 | stream = (struct hva_stream *)vq->bufs[buf->index]; | ||
558 | stream->bytesused = buf->bytesused; | ||
559 | } | ||
560 | |||
561 | return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf); | ||
562 | } | ||
563 | |||
564 | /* V4L2 ioctl ops */ | ||
565 | static const struct v4l2_ioctl_ops hva_ioctl_ops = { | ||
566 | .vidioc_querycap = hva_querycap, | ||
567 | .vidioc_enum_fmt_vid_cap = hva_enum_fmt_stream, | ||
568 | .vidioc_enum_fmt_vid_out = hva_enum_fmt_frame, | ||
569 | .vidioc_g_fmt_vid_cap = hva_g_fmt_stream, | ||
570 | .vidioc_g_fmt_vid_out = hva_g_fmt_frame, | ||
571 | .vidioc_try_fmt_vid_cap = hva_try_fmt_stream, | ||
572 | .vidioc_try_fmt_vid_out = hva_try_fmt_frame, | ||
573 | .vidioc_s_fmt_vid_cap = hva_s_fmt_stream, | ||
574 | .vidioc_s_fmt_vid_out = hva_s_fmt_frame, | ||
575 | .vidioc_g_parm = hva_g_parm, | ||
576 | .vidioc_s_parm = hva_s_parm, | ||
577 | .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, | ||
578 | .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, | ||
579 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, | ||
580 | .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, | ||
581 | .vidioc_qbuf = hva_qbuf, | ||
582 | .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, | ||
583 | .vidioc_streamon = v4l2_m2m_ioctl_streamon, | ||
584 | .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, | ||
585 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
586 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
587 | }; | ||
588 | |||
589 | /* | ||
590 | * V4L2 control operations | ||
591 | */ | ||
592 | |||
593 | static int hva_s_ctrl(struct v4l2_ctrl *ctrl) | ||
594 | { | ||
595 | struct hva_ctx *ctx = container_of(ctrl->handler, struct hva_ctx, | ||
596 | ctrl_handler); | ||
597 | struct device *dev = ctx_to_dev(ctx); | ||
598 | |||
599 | dev_dbg(dev, "%s S_CTRL: id = %d, val = %d\n", ctx->name, | ||
600 | ctrl->id, ctrl->val); | ||
601 | |||
602 | switch (ctrl->id) { | ||
603 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | ||
604 | ctx->ctrls.bitrate_mode = ctrl->val; | ||
605 | break; | ||
606 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
607 | ctx->ctrls.gop_size = ctrl->val; | ||
608 | break; | ||
609 | case V4L2_CID_MPEG_VIDEO_BITRATE: | ||
610 | ctx->ctrls.bitrate = ctrl->val; | ||
611 | break; | ||
612 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
613 | ctx->ctrls.aspect = ctrl->val; | ||
614 | break; | ||
615 | case V4L2_CID_MPEG_VIDEO_H264_PROFILE: | ||
616 | ctx->ctrls.profile = ctrl->val; | ||
617 | if (ctx->flags & HVA_FLAG_STREAMINFO) | ||
618 | snprintf(ctx->streaminfo.profile, | ||
619 | sizeof(ctx->streaminfo.profile), | ||
620 | "%s profile", | ||
621 | v4l2_ctrl_get_menu(ctrl->id)[ctrl->val]); | ||
622 | break; | ||
623 | case V4L2_CID_MPEG_VIDEO_H264_LEVEL: | ||
624 | ctx->ctrls.level = ctrl->val; | ||
625 | if (ctx->flags & HVA_FLAG_STREAMINFO) | ||
626 | snprintf(ctx->streaminfo.level, | ||
627 | sizeof(ctx->streaminfo.level), | ||
628 | "level %s", | ||
629 | v4l2_ctrl_get_menu(ctrl->id)[ctrl->val]); | ||
630 | break; | ||
631 | case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: | ||
632 | ctx->ctrls.entropy_mode = ctrl->val; | ||
633 | break; | ||
634 | case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: | ||
635 | ctx->ctrls.cpb_size = ctrl->val; | ||
636 | break; | ||
637 | case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: | ||
638 | ctx->ctrls.dct8x8 = ctrl->val; | ||
639 | break; | ||
640 | case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: | ||
641 | ctx->ctrls.qpmin = ctrl->val; | ||
642 | break; | ||
643 | case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: | ||
644 | ctx->ctrls.qpmax = ctrl->val; | ||
645 | break; | ||
646 | case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: | ||
647 | ctx->ctrls.vui_sar = ctrl->val; | ||
648 | break; | ||
649 | case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: | ||
650 | ctx->ctrls.vui_sar_idc = ctrl->val; | ||
651 | break; | ||
652 | case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: | ||
653 | ctx->ctrls.sei_fp = ctrl->val; | ||
654 | break; | ||
655 | case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: | ||
656 | ctx->ctrls.sei_fp_type = ctrl->val; | ||
657 | break; | ||
658 | default: | ||
659 | dev_dbg(dev, "%s S_CTRL: invalid control (id = %d)\n", | ||
660 | ctx->name, ctrl->id); | ||
661 | return -EINVAL; | ||
662 | } | ||
663 | |||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | /* V4L2 control ops */ | ||
668 | static const struct v4l2_ctrl_ops hva_ctrl_ops = { | ||
669 | .s_ctrl = hva_s_ctrl, | ||
670 | }; | ||
671 | |||
672 | static int hva_ctrls_setup(struct hva_ctx *ctx) | ||
673 | { | ||
674 | struct device *dev = ctx_to_dev(ctx); | ||
675 | u64 mask; | ||
676 | enum v4l2_mpeg_video_h264_sei_fp_arrangement_type sei_fp_type = | ||
677 | V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM; | ||
678 | |||
679 | v4l2_ctrl_handler_init(&ctx->ctrl_handler, 15); | ||
680 | |||
681 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
682 | V4L2_CID_MPEG_VIDEO_BITRATE_MODE, | ||
683 | V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, | ||
684 | 0, | ||
685 | V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); | ||
686 | |||
687 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
688 | V4L2_CID_MPEG_VIDEO_GOP_SIZE, | ||
689 | 1, 60, 1, 16); | ||
690 | |||
691 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
692 | V4L2_CID_MPEG_VIDEO_BITRATE, | ||
693 | 1000, 60000000, 1000, 20000000); | ||
694 | |||
695 | mask = ~(1 << V4L2_MPEG_VIDEO_ASPECT_1x1); | ||
696 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
697 | V4L2_CID_MPEG_VIDEO_ASPECT, | ||
698 | V4L2_MPEG_VIDEO_ASPECT_1x1, | ||
699 | mask, | ||
700 | V4L2_MPEG_VIDEO_ASPECT_1x1); | ||
701 | |||
702 | mask = ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | | ||
703 | (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | | ||
704 | (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | | ||
705 | (1 << V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH)); | ||
706 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
707 | V4L2_CID_MPEG_VIDEO_H264_PROFILE, | ||
708 | V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH, | ||
709 | mask, | ||
710 | V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); | ||
711 | |||
712 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
713 | V4L2_CID_MPEG_VIDEO_H264_LEVEL, | ||
714 | V4L2_MPEG_VIDEO_H264_LEVEL_4_2, | ||
715 | 0, | ||
716 | V4L2_MPEG_VIDEO_H264_LEVEL_4_0); | ||
717 | |||
718 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
719 | V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, | ||
720 | V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, | ||
721 | 0, | ||
722 | V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC); | ||
723 | |||
724 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
725 | V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, | ||
726 | 1, 10000, 1, 3000); | ||
727 | |||
728 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
729 | V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, | ||
730 | 0, 1, 1, 0); | ||
731 | |||
732 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
733 | V4L2_CID_MPEG_VIDEO_H264_MIN_QP, | ||
734 | 0, 51, 1, 5); | ||
735 | |||
736 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
737 | V4L2_CID_MPEG_VIDEO_H264_MAX_QP, | ||
738 | 0, 51, 1, 51); | ||
739 | |||
740 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
741 | V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE, | ||
742 | 0, 1, 1, 1); | ||
743 | |||
744 | mask = ~(1 << V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1); | ||
745 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
746 | V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC, | ||
747 | V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1, | ||
748 | mask, | ||
749 | V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1); | ||
750 | |||
751 | v4l2_ctrl_new_std(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
752 | V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING, | ||
753 | 0, 1, 1, 0); | ||
754 | |||
755 | mask = ~(1 << sei_fp_type); | ||
756 | v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &hva_ctrl_ops, | ||
757 | V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE, | ||
758 | sei_fp_type, | ||
759 | mask, | ||
760 | sei_fp_type); | ||
761 | |||
762 | if (ctx->ctrl_handler.error) { | ||
763 | int err = ctx->ctrl_handler.error; | ||
764 | |||
765 | dev_dbg(dev, "%s controls setup failed (%d)\n", | ||
766 | ctx->name, err); | ||
767 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | ||
768 | return err; | ||
769 | } | ||
770 | |||
771 | v4l2_ctrl_handler_setup(&ctx->ctrl_handler); | ||
772 | |||
773 | /* set default time per frame */ | ||
774 | ctx->ctrls.time_per_frame.numerator = HVA_DEFAULT_FRAME_NUM; | ||
775 | ctx->ctrls.time_per_frame.denominator = HVA_DEFAULT_FRAME_DEN; | ||
776 | |||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | /* | ||
781 | * mem-to-mem operations | ||
782 | */ | ||
783 | |||
784 | static void hva_run_work(struct work_struct *work) | ||
785 | { | ||
786 | struct hva_ctx *ctx = container_of(work, struct hva_ctx, run_work); | ||
787 | struct vb2_v4l2_buffer *src_buf, *dst_buf; | ||
788 | const struct hva_enc *enc = ctx->enc; | ||
789 | struct hva_frame *frame; | ||
790 | struct hva_stream *stream; | ||
791 | int ret; | ||
792 | |||
793 | /* protect instance against reentrancy */ | ||
794 | mutex_lock(&ctx->lock); | ||
795 | |||
796 | src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); | ||
797 | dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); | ||
798 | |||
799 | frame = to_hva_frame(src_buf); | ||
800 | stream = to_hva_stream(dst_buf); | ||
801 | frame->vbuf.sequence = ctx->frame_num++; | ||
802 | |||
803 | ret = enc->encode(ctx, frame, stream); | ||
804 | |||
805 | vb2_set_plane_payload(&dst_buf->vb2_buf, 0, stream->bytesused); | ||
806 | if (ret) { | ||
807 | v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); | ||
808 | v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); | ||
809 | } else { | ||
810 | /* propagate frame timestamp */ | ||
811 | dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; | ||
812 | dst_buf->field = V4L2_FIELD_NONE; | ||
813 | dst_buf->sequence = ctx->stream_num - 1; | ||
814 | |||
815 | v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); | ||
816 | v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); | ||
817 | } | ||
818 | |||
819 | mutex_unlock(&ctx->lock); | ||
820 | |||
821 | v4l2_m2m_job_finish(ctx->hva_dev->m2m_dev, ctx->fh.m2m_ctx); | ||
822 | } | ||
823 | |||
824 | static void hva_device_run(void *priv) | ||
825 | { | ||
826 | struct hva_ctx *ctx = priv; | ||
827 | struct hva_dev *hva = ctx_to_hdev(ctx); | ||
828 | |||
829 | queue_work(hva->work_queue, &ctx->run_work); | ||
830 | } | ||
831 | |||
832 | static void hva_job_abort(void *priv) | ||
833 | { | ||
834 | struct hva_ctx *ctx = priv; | ||
835 | struct device *dev = ctx_to_dev(ctx); | ||
836 | |||
837 | dev_dbg(dev, "%s aborting job\n", ctx->name); | ||
838 | |||
839 | ctx->aborting = true; | ||
840 | } | ||
841 | |||
842 | static int hva_job_ready(void *priv) | ||
843 | { | ||
844 | struct hva_ctx *ctx = priv; | ||
845 | struct device *dev = ctx_to_dev(ctx); | ||
846 | |||
847 | if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) { | ||
848 | dev_dbg(dev, "%s job not ready: no frame buffers\n", | ||
849 | ctx->name); | ||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) { | ||
854 | dev_dbg(dev, "%s job not ready: no stream buffers\n", | ||
855 | ctx->name); | ||
856 | return 0; | ||
857 | } | ||
858 | |||
859 | if (ctx->aborting) { | ||
860 | dev_dbg(dev, "%s job not ready: aborting\n", ctx->name); | ||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | return 1; | ||
865 | } | ||
866 | |||
867 | /* mem-to-mem ops */ | ||
868 | static const struct v4l2_m2m_ops hva_m2m_ops = { | ||
869 | .device_run = hva_device_run, | ||
870 | .job_abort = hva_job_abort, | ||
871 | .job_ready = hva_job_ready, | ||
872 | }; | ||
873 | |||
874 | /* | ||
875 | * VB2 queue operations | ||
876 | */ | ||
877 | |||
878 | static int hva_queue_setup(struct vb2_queue *vq, | ||
879 | unsigned int *num_buffers, unsigned int *num_planes, | ||
880 | unsigned int sizes[], struct device *alloc_devs[]) | ||
881 | { | ||
882 | struct hva_ctx *ctx = vb2_get_drv_priv(vq); | ||
883 | struct device *dev = ctx_to_dev(ctx); | ||
884 | unsigned int size; | ||
885 | |||
886 | dev_dbg(dev, "%s %s queue setup: num_buffers %d\n", ctx->name, | ||
887 | to_type_str(vq->type), *num_buffers); | ||
888 | |||
889 | size = vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT ? | ||
890 | ctx->frameinfo.size : ctx->max_stream_size; | ||
891 | |||
892 | if (*num_planes) | ||
893 | return sizes[0] < size ? -EINVAL : 0; | ||
894 | |||
895 | /* only one plane supported */ | ||
896 | *num_planes = 1; | ||
897 | sizes[0] = size; | ||
898 | |||
899 | return 0; | ||
900 | } | ||
901 | |||
902 | static int hva_buf_prepare(struct vb2_buffer *vb) | ||
903 | { | ||
904 | struct hva_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | ||
905 | struct device *dev = ctx_to_dev(ctx); | ||
906 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
907 | |||
908 | if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
909 | struct hva_frame *frame = to_hva_frame(vbuf); | ||
910 | |||
911 | if (vbuf->field == V4L2_FIELD_ANY) | ||
912 | vbuf->field = V4L2_FIELD_NONE; | ||
913 | if (vbuf->field != V4L2_FIELD_NONE) { | ||
914 | dev_dbg(dev, | ||
915 | "%s frame[%d] prepare: %d field not supported\n", | ||
916 | ctx->name, vb->index, vbuf->field); | ||
917 | return -EINVAL; | ||
918 | } | ||
919 | |||
920 | if (!frame->prepared) { | ||
921 | /* get memory addresses */ | ||
922 | frame->vaddr = vb2_plane_vaddr(&vbuf->vb2_buf, 0); | ||
923 | frame->paddr = vb2_dma_contig_plane_dma_addr( | ||
924 | &vbuf->vb2_buf, 0); | ||
925 | frame->info = ctx->frameinfo; | ||
926 | frame->prepared = true; | ||
927 | |||
928 | dev_dbg(dev, | ||
929 | "%s frame[%d] prepared; virt=%p, phy=%pad\n", | ||
930 | ctx->name, vb->index, | ||
931 | frame->vaddr, &frame->paddr); | ||
932 | } | ||
933 | } else { | ||
934 | struct hva_stream *stream = to_hva_stream(vbuf); | ||
935 | |||
936 | if (!stream->prepared) { | ||
937 | /* get memory addresses */ | ||
938 | stream->vaddr = vb2_plane_vaddr(&vbuf->vb2_buf, 0); | ||
939 | stream->paddr = vb2_dma_contig_plane_dma_addr( | ||
940 | &vbuf->vb2_buf, 0); | ||
941 | stream->size = vb2_plane_size(&vbuf->vb2_buf, 0); | ||
942 | stream->prepared = true; | ||
943 | |||
944 | dev_dbg(dev, | ||
945 | "%s stream[%d] prepared; virt=%p, phy=%pad\n", | ||
946 | ctx->name, vb->index, | ||
947 | stream->vaddr, &stream->paddr); | ||
948 | } | ||
949 | } | ||
950 | |||
951 | return 0; | ||
952 | } | ||
953 | |||
954 | static void hva_buf_queue(struct vb2_buffer *vb) | ||
955 | { | ||
956 | struct hva_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | ||
957 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
958 | |||
959 | if (ctx->fh.m2m_ctx) | ||
960 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); | ||
961 | } | ||
962 | |||
963 | static int hva_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
964 | { | ||
965 | struct hva_ctx *ctx = vb2_get_drv_priv(vq); | ||
966 | struct hva_dev *hva = ctx_to_hdev(ctx); | ||
967 | struct device *dev = ctx_to_dev(ctx); | ||
968 | struct vb2_v4l2_buffer *vbuf; | ||
969 | int ret; | ||
970 | unsigned int i; | ||
971 | bool found = false; | ||
972 | |||
973 | dev_dbg(dev, "%s %s start streaming\n", ctx->name, | ||
974 | to_type_str(vq->type)); | ||
975 | |||
976 | /* open encoder when both start_streaming have been called */ | ||
977 | if (V4L2_TYPE_IS_OUTPUT(vq->type)) { | ||
978 | if (!vb2_start_streaming_called(&ctx->fh.m2m_ctx->cap_q_ctx.q)) | ||
979 | return 0; | ||
980 | } else { | ||
981 | if (!vb2_start_streaming_called(&ctx->fh.m2m_ctx->out_q_ctx.q)) | ||
982 | return 0; | ||
983 | } | ||
984 | |||
985 | /* store the instance context in the instances array */ | ||
986 | for (i = 0; i < HVA_MAX_INSTANCES; i++) { | ||
987 | if (!hva->instances[i]) { | ||
988 | hva->instances[i] = ctx; | ||
989 | /* save the context identifier in the context */ | ||
990 | ctx->id = i; | ||
991 | found = true; | ||
992 | break; | ||
993 | } | ||
994 | } | ||
995 | |||
996 | if (!found) { | ||
997 | dev_err(dev, "%s maximum instances reached\n", ctx->name); | ||
998 | ret = -ENOMEM; | ||
999 | goto err; | ||
1000 | } | ||
1001 | |||
1002 | hva->nb_of_instances++; | ||
1003 | |||
1004 | if (!ctx->enc) { | ||
1005 | ret = hva_open_encoder(ctx, | ||
1006 | ctx->streaminfo.streamformat, | ||
1007 | ctx->frameinfo.pixelformat, | ||
1008 | &ctx->enc); | ||
1009 | if (ret < 0) | ||
1010 | goto err_ctx; | ||
1011 | } | ||
1012 | |||
1013 | return 0; | ||
1014 | |||
1015 | err_ctx: | ||
1016 | hva->instances[ctx->id] = NULL; | ||
1017 | hva->nb_of_instances--; | ||
1018 | err: | ||
1019 | if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
1020 | /* return of all pending buffers to vb2 (in queued state) */ | ||
1021 | while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) | ||
1022 | v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_QUEUED); | ||
1023 | } else { | ||
1024 | /* return of all pending buffers to vb2 (in queued state) */ | ||
1025 | while ((vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) | ||
1026 | v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_QUEUED); | ||
1027 | } | ||
1028 | |||
1029 | return ret; | ||
1030 | } | ||
1031 | |||
1032 | static void hva_stop_streaming(struct vb2_queue *vq) | ||
1033 | { | ||
1034 | struct hva_ctx *ctx = vb2_get_drv_priv(vq); | ||
1035 | struct hva_dev *hva = ctx_to_hdev(ctx); | ||
1036 | struct device *dev = ctx_to_dev(ctx); | ||
1037 | const struct hva_enc *enc = ctx->enc; | ||
1038 | struct vb2_v4l2_buffer *vbuf; | ||
1039 | |||
1040 | dev_dbg(dev, "%s %s stop streaming\n", ctx->name, | ||
1041 | to_type_str(vq->type)); | ||
1042 | |||
1043 | if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
1044 | /* return of all pending buffers to vb2 (in error state) */ | ||
1045 | ctx->frame_num = 0; | ||
1046 | while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) | ||
1047 | v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); | ||
1048 | } else { | ||
1049 | /* return of all pending buffers to vb2 (in error state) */ | ||
1050 | ctx->stream_num = 0; | ||
1051 | while ((vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) | ||
1052 | v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); | ||
1053 | } | ||
1054 | |||
1055 | if ((V4L2_TYPE_IS_OUTPUT(vq->type) && | ||
1056 | vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)) || | ||
1057 | (!V4L2_TYPE_IS_OUTPUT(vq->type) && | ||
1058 | vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))) { | ||
1059 | dev_dbg(dev, "%s %s out=%d cap=%d\n", | ||
1060 | ctx->name, to_type_str(vq->type), | ||
1061 | vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q), | ||
1062 | vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)); | ||
1063 | return; | ||
1064 | } | ||
1065 | |||
1066 | /* close encoder when both stop_streaming have been called */ | ||
1067 | if (enc) { | ||
1068 | dev_dbg(dev, "%s %s encoder closed\n", ctx->name, enc->name); | ||
1069 | enc->close(ctx); | ||
1070 | ctx->enc = NULL; | ||
1071 | |||
1072 | /* clear instance context in instances array */ | ||
1073 | hva->instances[ctx->id] = NULL; | ||
1074 | hva->nb_of_instances--; | ||
1075 | } | ||
1076 | |||
1077 | ctx->aborting = false; | ||
1078 | } | ||
1079 | |||
1080 | /* VB2 queue ops */ | ||
1081 | static const struct vb2_ops hva_qops = { | ||
1082 | .queue_setup = hva_queue_setup, | ||
1083 | .buf_prepare = hva_buf_prepare, | ||
1084 | .buf_queue = hva_buf_queue, | ||
1085 | .start_streaming = hva_start_streaming, | ||
1086 | .stop_streaming = hva_stop_streaming, | ||
1087 | .wait_prepare = vb2_ops_wait_prepare, | ||
1088 | .wait_finish = vb2_ops_wait_finish, | ||
1089 | }; | ||
1090 | |||
1091 | /* | ||
1092 | * V4L2 file operations | ||
1093 | */ | ||
1094 | |||
1095 | static int queue_init(struct hva_ctx *ctx, struct vb2_queue *vq) | ||
1096 | { | ||
1097 | vq->io_modes = VB2_MMAP | VB2_DMABUF; | ||
1098 | vq->drv_priv = ctx; | ||
1099 | vq->ops = &hva_qops; | ||
1100 | vq->mem_ops = &vb2_dma_contig_memops; | ||
1101 | vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | ||
1102 | vq->lock = &ctx->hva_dev->lock; | ||
1103 | |||
1104 | return vb2_queue_init(vq); | ||
1105 | } | ||
1106 | |||
1107 | static int hva_queue_init(void *priv, struct vb2_queue *src_vq, | ||
1108 | struct vb2_queue *dst_vq) | ||
1109 | { | ||
1110 | struct hva_ctx *ctx = priv; | ||
1111 | int ret; | ||
1112 | |||
1113 | src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
1114 | src_vq->buf_struct_size = sizeof(struct hva_frame); | ||
1115 | src_vq->min_buffers_needed = MIN_FRAMES; | ||
1116 | src_vq->dev = ctx->hva_dev->dev; | ||
1117 | |||
1118 | ret = queue_init(ctx, src_vq); | ||
1119 | if (ret) | ||
1120 | return ret; | ||
1121 | |||
1122 | dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1123 | dst_vq->buf_struct_size = sizeof(struct hva_stream); | ||
1124 | dst_vq->min_buffers_needed = MIN_STREAMS; | ||
1125 | dst_vq->dev = ctx->hva_dev->dev; | ||
1126 | |||
1127 | return queue_init(ctx, dst_vq); | ||
1128 | } | ||
1129 | |||
1130 | static int hva_open(struct file *file) | ||
1131 | { | ||
1132 | struct hva_dev *hva = video_drvdata(file); | ||
1133 | struct device *dev = hva_to_dev(hva); | ||
1134 | struct hva_ctx *ctx; | ||
1135 | int ret; | ||
1136 | |||
1137 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | ||
1138 | if (!ctx) { | ||
1139 | ret = -ENOMEM; | ||
1140 | goto out; | ||
1141 | } | ||
1142 | ctx->hva_dev = hva; | ||
1143 | |||
1144 | INIT_WORK(&ctx->run_work, hva_run_work); | ||
1145 | v4l2_fh_init(&ctx->fh, video_devdata(file)); | ||
1146 | file->private_data = &ctx->fh; | ||
1147 | v4l2_fh_add(&ctx->fh); | ||
1148 | |||
1149 | ret = hva_ctrls_setup(ctx); | ||
1150 | if (ret) { | ||
1151 | dev_err(dev, "%s [x:x] failed to setup controls\n", | ||
1152 | HVA_PREFIX); | ||
1153 | goto err_fh; | ||
1154 | } | ||
1155 | ctx->fh.ctrl_handler = &ctx->ctrl_handler; | ||
1156 | |||
1157 | mutex_init(&ctx->lock); | ||
1158 | |||
1159 | ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(hva->m2m_dev, ctx, | ||
1160 | &hva_queue_init); | ||
1161 | if (IS_ERR(ctx->fh.m2m_ctx)) { | ||
1162 | ret = PTR_ERR(ctx->fh.m2m_ctx); | ||
1163 | dev_err(dev, "%s failed to initialize m2m context (%d)\n", | ||
1164 | HVA_PREFIX, ret); | ||
1165 | goto err_ctrls; | ||
1166 | } | ||
1167 | |||
1168 | /* set the instance name */ | ||
1169 | mutex_lock(&hva->lock); | ||
1170 | hva->instance_id++; | ||
1171 | snprintf(ctx->name, sizeof(ctx->name), "[%3d:----]", | ||
1172 | hva->instance_id); | ||
1173 | mutex_unlock(&hva->lock); | ||
1174 | |||
1175 | /* default parameters for frame and stream */ | ||
1176 | set_default_params(ctx); | ||
1177 | |||
1178 | dev_info(dev, "%s encoder instance created\n", ctx->name); | ||
1179 | |||
1180 | return 0; | ||
1181 | |||
1182 | err_ctrls: | ||
1183 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | ||
1184 | err_fh: | ||
1185 | v4l2_fh_del(&ctx->fh); | ||
1186 | v4l2_fh_exit(&ctx->fh); | ||
1187 | kfree(ctx); | ||
1188 | out: | ||
1189 | return ret; | ||
1190 | } | ||
1191 | |||
1192 | static int hva_release(struct file *file) | ||
1193 | { | ||
1194 | struct hva_ctx *ctx = fh_to_ctx(file->private_data); | ||
1195 | struct hva_dev *hva = ctx_to_hdev(ctx); | ||
1196 | struct device *dev = ctx_to_dev(ctx); | ||
1197 | const struct hva_enc *enc = ctx->enc; | ||
1198 | |||
1199 | if (enc) { | ||
1200 | dev_dbg(dev, "%s %s encoder closed\n", ctx->name, enc->name); | ||
1201 | enc->close(ctx); | ||
1202 | ctx->enc = NULL; | ||
1203 | |||
1204 | /* clear instance context in instances array */ | ||
1205 | hva->instances[ctx->id] = NULL; | ||
1206 | hva->nb_of_instances--; | ||
1207 | } | ||
1208 | |||
1209 | v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); | ||
1210 | |||
1211 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | ||
1212 | |||
1213 | v4l2_fh_del(&ctx->fh); | ||
1214 | v4l2_fh_exit(&ctx->fh); | ||
1215 | |||
1216 | dev_info(dev, "%s encoder instance released\n", ctx->name); | ||
1217 | |||
1218 | kfree(ctx); | ||
1219 | |||
1220 | return 0; | ||
1221 | } | ||
1222 | |||
1223 | /* V4L2 file ops */ | ||
1224 | static const struct v4l2_file_operations hva_fops = { | ||
1225 | .owner = THIS_MODULE, | ||
1226 | .open = hva_open, | ||
1227 | .release = hva_release, | ||
1228 | .unlocked_ioctl = video_ioctl2, | ||
1229 | .mmap = v4l2_m2m_fop_mmap, | ||
1230 | .poll = v4l2_m2m_fop_poll, | ||
1231 | }; | ||
1232 | |||
1233 | /* | ||
1234 | * Platform device operations | ||
1235 | */ | ||
1236 | |||
1237 | static int hva_register_device(struct hva_dev *hva) | ||
1238 | { | ||
1239 | int ret; | ||
1240 | struct video_device *vdev; | ||
1241 | struct device *dev; | ||
1242 | |||
1243 | if (!hva) | ||
1244 | return -ENODEV; | ||
1245 | dev = hva_to_dev(hva); | ||
1246 | |||
1247 | hva->m2m_dev = v4l2_m2m_init(&hva_m2m_ops); | ||
1248 | if (IS_ERR(hva->m2m_dev)) { | ||
1249 | dev_err(dev, "%s failed to initialize v4l2-m2m device\n", | ||
1250 | HVA_PREFIX); | ||
1251 | ret = PTR_ERR(hva->m2m_dev); | ||
1252 | goto err; | ||
1253 | } | ||
1254 | |||
1255 | vdev = video_device_alloc(); | ||
1256 | if (!vdev) { | ||
1257 | dev_err(dev, "%s failed to allocate video device\n", | ||
1258 | HVA_PREFIX); | ||
1259 | ret = -ENOMEM; | ||
1260 | goto err_m2m_release; | ||
1261 | } | ||
1262 | |||
1263 | vdev->fops = &hva_fops; | ||
1264 | vdev->ioctl_ops = &hva_ioctl_ops; | ||
1265 | vdev->release = video_device_release; | ||
1266 | vdev->lock = &hva->lock; | ||
1267 | vdev->vfl_dir = VFL_DIR_M2M; | ||
1268 | vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; | ||
1269 | vdev->v4l2_dev = &hva->v4l2_dev; | ||
1270 | snprintf(vdev->name, sizeof(vdev->name), "%s%lx", HVA_NAME, | ||
1271 | hva->ip_version); | ||
1272 | |||
1273 | ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | ||
1274 | if (ret) { | ||
1275 | dev_err(dev, "%s failed to register video device\n", | ||
1276 | HVA_PREFIX); | ||
1277 | goto err_vdev_release; | ||
1278 | } | ||
1279 | |||
1280 | hva->vdev = vdev; | ||
1281 | video_set_drvdata(vdev, hva); | ||
1282 | return 0; | ||
1283 | |||
1284 | err_vdev_release: | ||
1285 | video_device_release(vdev); | ||
1286 | err_m2m_release: | ||
1287 | v4l2_m2m_release(hva->m2m_dev); | ||
1288 | err: | ||
1289 | return ret; | ||
1290 | } | ||
1291 | |||
1292 | static void hva_unregister_device(struct hva_dev *hva) | ||
1293 | { | ||
1294 | if (!hva) | ||
1295 | return; | ||
1296 | |||
1297 | if (hva->m2m_dev) | ||
1298 | v4l2_m2m_release(hva->m2m_dev); | ||
1299 | |||
1300 | video_unregister_device(hva->vdev); | ||
1301 | } | ||
1302 | |||
1303 | static int hva_probe(struct platform_device *pdev) | ||
1304 | { | ||
1305 | struct hva_dev *hva; | ||
1306 | struct device *dev = &pdev->dev; | ||
1307 | int ret; | ||
1308 | |||
1309 | hva = devm_kzalloc(dev, sizeof(*hva), GFP_KERNEL); | ||
1310 | if (!hva) { | ||
1311 | ret = -ENOMEM; | ||
1312 | goto err; | ||
1313 | } | ||
1314 | |||
1315 | hva->dev = dev; | ||
1316 | hva->pdev = pdev; | ||
1317 | platform_set_drvdata(pdev, hva); | ||
1318 | |||
1319 | mutex_init(&hva->lock); | ||
1320 | |||
1321 | /* probe hardware */ | ||
1322 | ret = hva_hw_probe(pdev, hva); | ||
1323 | if (ret) | ||
1324 | goto err; | ||
1325 | |||
1326 | /* register all available encoders */ | ||
1327 | register_encoders(hva); | ||
1328 | |||
1329 | /* register all supported formats */ | ||
1330 | register_formats(hva); | ||
1331 | |||
1332 | /* register on V4L2 */ | ||
1333 | ret = v4l2_device_register(dev, &hva->v4l2_dev); | ||
1334 | if (ret) { | ||
1335 | dev_err(dev, "%s %s failed to register V4L2 device\n", | ||
1336 | HVA_PREFIX, HVA_NAME); | ||
1337 | goto err_hw; | ||
1338 | } | ||
1339 | |||
1340 | hva->work_queue = create_workqueue(HVA_NAME); | ||
1341 | if (!hva->work_queue) { | ||
1342 | dev_err(dev, "%s %s failed to allocate work queue\n", | ||
1343 | HVA_PREFIX, HVA_NAME); | ||
1344 | ret = -ENOMEM; | ||
1345 | goto err_v4l2; | ||
1346 | } | ||
1347 | |||
1348 | /* register device */ | ||
1349 | ret = hva_register_device(hva); | ||
1350 | if (ret) | ||
1351 | goto err_work_queue; | ||
1352 | |||
1353 | dev_info(dev, "%s %s registered as /dev/video%d\n", HVA_PREFIX, | ||
1354 | HVA_NAME, hva->vdev->num); | ||
1355 | |||
1356 | return 0; | ||
1357 | |||
1358 | err_work_queue: | ||
1359 | destroy_workqueue(hva->work_queue); | ||
1360 | err_v4l2: | ||
1361 | v4l2_device_unregister(&hva->v4l2_dev); | ||
1362 | err_hw: | ||
1363 | hva_hw_remove(hva); | ||
1364 | err: | ||
1365 | return ret; | ||
1366 | } | ||
1367 | |||
1368 | static int hva_remove(struct platform_device *pdev) | ||
1369 | { | ||
1370 | struct hva_dev *hva = platform_get_drvdata(pdev); | ||
1371 | struct device *dev = hva_to_dev(hva); | ||
1372 | |||
1373 | hva_unregister_device(hva); | ||
1374 | |||
1375 | destroy_workqueue(hva->work_queue); | ||
1376 | |||
1377 | hva_hw_remove(hva); | ||
1378 | |||
1379 | v4l2_device_unregister(&hva->v4l2_dev); | ||
1380 | |||
1381 | dev_info(dev, "%s %s removed\n", HVA_PREFIX, pdev->name); | ||
1382 | |||
1383 | return 0; | ||
1384 | } | ||
1385 | |||
1386 | /* PM ops */ | ||
1387 | static const struct dev_pm_ops hva_pm_ops = { | ||
1388 | .runtime_suspend = hva_hw_runtime_suspend, | ||
1389 | .runtime_resume = hva_hw_runtime_resume, | ||
1390 | }; | ||
1391 | |||
1392 | static const struct of_device_id hva_match_types[] = { | ||
1393 | { | ||
1394 | .compatible = "st,st-hva", | ||
1395 | }, | ||
1396 | { /* end node */ } | ||
1397 | }; | ||
1398 | |||
1399 | MODULE_DEVICE_TABLE(of, hva_match_types); | ||
1400 | |||
1401 | static struct platform_driver hva_driver = { | ||
1402 | .probe = hva_probe, | ||
1403 | .remove = hva_remove, | ||
1404 | .driver = { | ||
1405 | .name = HVA_NAME, | ||
1406 | .of_match_table = hva_match_types, | ||
1407 | .pm = &hva_pm_ops, | ||
1408 | }, | ||
1409 | }; | ||
1410 | |||
1411 | module_platform_driver(hva_driver); | ||
1412 | |||
1413 | MODULE_LICENSE("GPL"); | ||
1414 | MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>"); | ||
1415 | MODULE_DESCRIPTION("STMicroelectronics HVA video encoder V4L2 driver"); | ||
diff --git a/drivers/media/platform/sti/hva/hva.h b/drivers/media/platform/sti/hva/hva.h new file mode 100644 index 000000000000..caa580825541 --- /dev/null +++ b/drivers/media/platform/sti/hva/hva.h | |||
@@ -0,0 +1,315 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2015 | ||
3 | * Authors: Yannick Fertre <yannick.fertre@st.com> | ||
4 | * Hugues Fruchet <hugues.fruchet@st.com> | ||
5 | * License terms: GNU General Public License (GPL), version 2 | ||
6 | */ | ||
7 | |||
8 | #ifndef HVA_H | ||
9 | #define HVA_H | ||
10 | |||
11 | #include <media/v4l2-ctrls.h> | ||
12 | #include <media/v4l2-device.h> | ||
13 | #include <media/videobuf2-v4l2.h> | ||
14 | #include <media/v4l2-mem2mem.h> | ||
15 | |||
16 | #define fh_to_ctx(f) (container_of(f, struct hva_ctx, fh)) | ||
17 | |||
18 | #define hva_to_dev(h) (h->dev) | ||
19 | |||
20 | #define ctx_to_dev(c) (c->hva_dev->dev) | ||
21 | |||
22 | #define ctx_to_hdev(c) (c->hva_dev) | ||
23 | |||
24 | #define HVA_PREFIX "[---:----]" | ||
25 | |||
26 | extern const struct hva_enc nv12h264enc; | ||
27 | extern const struct hva_enc nv21h264enc; | ||
28 | |||
29 | /** | ||
30 | * struct hva_frameinfo - information about hva frame | ||
31 | * | ||
32 | * @pixelformat: fourcc code for uncompressed video format | ||
33 | * @width: width of frame | ||
34 | * @height: height of frame | ||
35 | * @aligned_width: width of frame (with encoder alignment constraint) | ||
36 | * @aligned_height: height of frame (with encoder alignment constraint) | ||
37 | * @size: maximum size in bytes required for data | ||
38 | */ | ||
39 | struct hva_frameinfo { | ||
40 | u32 pixelformat; | ||
41 | u32 width; | ||
42 | u32 height; | ||
43 | u32 aligned_width; | ||
44 | u32 aligned_height; | ||
45 | u32 size; | ||
46 | }; | ||
47 | |||
48 | /** | ||
49 | * struct hva_streaminfo - information about hva stream | ||
50 | * | ||
51 | * @streamformat: fourcc code of compressed video format (H.264...) | ||
52 | * @width: width of stream | ||
53 | * @height: height of stream | ||
54 | * @profile: profile string | ||
55 | * @level: level string | ||
56 | */ | ||
57 | struct hva_streaminfo { | ||
58 | u32 streamformat; | ||
59 | u32 width; | ||
60 | u32 height; | ||
61 | u8 profile[32]; | ||
62 | u8 level[32]; | ||
63 | }; | ||
64 | |||
65 | /** | ||
66 | * struct hva_controls - hva controls set | ||
67 | * | ||
68 | * @time_per_frame: time per frame in seconds | ||
69 | * @bitrate_mode: bitrate mode (constant bitrate or variable bitrate) | ||
70 | * @gop_size: groupe of picture size | ||
71 | * @bitrate: bitrate (in bps) | ||
72 | * @aspect: video aspect | ||
73 | * @profile: H.264 profile | ||
74 | * @level: H.264 level | ||
75 | * @entropy_mode: H.264 entropy mode (CABAC or CVLC) | ||
76 | * @cpb_size: coded picture buffer size (in kB) | ||
77 | * @dct8x8: transform mode 8x8 enable | ||
78 | * @qpmin: minimum quantizer | ||
79 | * @qpmax: maximum quantizer | ||
80 | * @vui_sar: pixel aspect ratio enable | ||
81 | * @vui_sar_idc: pixel aspect ratio identifier | ||
82 | * @sei_fp: sei frame packing arrangement enable | ||
83 | * @sei_fp_type: sei frame packing arrangement type | ||
84 | */ | ||
85 | struct hva_controls { | ||
86 | struct v4l2_fract time_per_frame; | ||
87 | enum v4l2_mpeg_video_bitrate_mode bitrate_mode; | ||
88 | u32 gop_size; | ||
89 | u32 bitrate; | ||
90 | enum v4l2_mpeg_video_aspect aspect; | ||
91 | enum v4l2_mpeg_video_h264_profile profile; | ||
92 | enum v4l2_mpeg_video_h264_level level; | ||
93 | enum v4l2_mpeg_video_h264_entropy_mode entropy_mode; | ||
94 | u32 cpb_size; | ||
95 | bool dct8x8; | ||
96 | u32 qpmin; | ||
97 | u32 qpmax; | ||
98 | bool vui_sar; | ||
99 | enum v4l2_mpeg_video_h264_vui_sar_idc vui_sar_idc; | ||
100 | bool sei_fp; | ||
101 | enum v4l2_mpeg_video_h264_sei_fp_arrangement_type sei_fp_type; | ||
102 | }; | ||
103 | |||
104 | /** | ||
105 | * struct hva_frame - hva frame buffer (output) | ||
106 | * | ||
107 | * @vbuf: video buffer information for V4L2 | ||
108 | * @list: V4L2 m2m list that the frame belongs to | ||
109 | * @info: frame information (width, height, format, alignment...) | ||
110 | * @paddr: physical address (for hardware) | ||
111 | * @vaddr: virtual address (kernel can read/write) | ||
112 | * @prepared: true if vaddr/paddr are resolved | ||
113 | */ | ||
114 | struct hva_frame { | ||
115 | struct vb2_v4l2_buffer vbuf; | ||
116 | struct list_head list; | ||
117 | struct hva_frameinfo info; | ||
118 | dma_addr_t paddr; | ||
119 | void *vaddr; | ||
120 | bool prepared; | ||
121 | }; | ||
122 | |||
123 | /* | ||
124 | * to_hva_frame() - cast struct vb2_v4l2_buffer * to struct hva_frame * | ||
125 | */ | ||
126 | #define to_hva_frame(vb) \ | ||
127 | container_of(vb, struct hva_frame, vbuf) | ||
128 | |||
129 | /** | ||
130 | * struct hva_stream - hva stream buffer (capture) | ||
131 | * | ||
132 | * @v4l2: video buffer information for V4L2 | ||
133 | * @list: V4L2 m2m list that the frame belongs to | ||
134 | * @paddr: physical address (for hardware) | ||
135 | * @vaddr: virtual address (kernel can read/write) | ||
136 | * @prepared: true if vaddr/paddr are resolved | ||
137 | * @size: size of the buffer in bytes | ||
138 | * @bytesused: number of bytes occupied by data in the buffer | ||
139 | */ | ||
140 | struct hva_stream { | ||
141 | struct vb2_v4l2_buffer vbuf; | ||
142 | struct list_head list; | ||
143 | dma_addr_t paddr; | ||
144 | void *vaddr; | ||
145 | bool prepared; | ||
146 | unsigned int size; | ||
147 | unsigned int bytesused; | ||
148 | }; | ||
149 | |||
150 | /* | ||
151 | * to_hva_stream() - cast struct vb2_v4l2_buffer * to struct hva_stream * | ||
152 | */ | ||
153 | #define to_hva_stream(vb) \ | ||
154 | container_of(vb, struct hva_stream, vbuf) | ||
155 | |||
156 | struct hva_dev; | ||
157 | struct hva_enc; | ||
158 | |||
159 | /** | ||
160 | * struct hva_ctx - context of hva instance | ||
161 | * | ||
162 | * @hva_dev: the device that this instance is associated with | ||
163 | * @fh: V4L2 file handle | ||
164 | * @ctrl_handler: V4L2 controls handler | ||
165 | * @ctrls: hva controls set | ||
166 | * @id: instance identifier | ||
167 | * @aborting: true if current job aborted | ||
168 | * @name: instance name (debug purpose) | ||
169 | * @run_work: encode work | ||
170 | * @lock: mutex used to lock access of this context | ||
171 | * @flags: validity of streaminfo and frameinfo fields | ||
172 | * @frame_num: frame number | ||
173 | * @stream_num: stream number | ||
174 | * @max_stream_size: maximum size in bytes required for stream data | ||
175 | * @colorspace: colorspace identifier | ||
176 | * @xfer_func: transfer function identifier | ||
177 | * @ycbcr_enc: Y'CbCr encoding identifier | ||
178 | * @quantization: quantization identifier | ||
179 | * @streaminfo: stream properties | ||
180 | * @frameinfo: frame properties | ||
181 | * @enc: current encoder | ||
182 | * @priv: private codec data for this instance, allocated | ||
183 | * by encoder @open time | ||
184 | * @hw_err: true if hardware error detected | ||
185 | */ | ||
186 | struct hva_ctx { | ||
187 | struct hva_dev *hva_dev; | ||
188 | struct v4l2_fh fh; | ||
189 | struct v4l2_ctrl_handler ctrl_handler; | ||
190 | struct hva_controls ctrls; | ||
191 | u8 id; | ||
192 | bool aborting; | ||
193 | char name[100]; | ||
194 | struct work_struct run_work; | ||
195 | /* mutex protecting this data structure */ | ||
196 | struct mutex lock; | ||
197 | u32 flags; | ||
198 | u32 frame_num; | ||
199 | u32 stream_num; | ||
200 | u32 max_stream_size; | ||
201 | enum v4l2_colorspace colorspace; | ||
202 | enum v4l2_xfer_func xfer_func; | ||
203 | enum v4l2_ycbcr_encoding ycbcr_enc; | ||
204 | enum v4l2_quantization quantization; | ||
205 | struct hva_streaminfo streaminfo; | ||
206 | struct hva_frameinfo frameinfo; | ||
207 | struct hva_enc *enc; | ||
208 | void *priv; | ||
209 | bool hw_err; | ||
210 | }; | ||
211 | |||
212 | #define HVA_FLAG_STREAMINFO 0x0001 | ||
213 | #define HVA_FLAG_FRAMEINFO 0x0002 | ||
214 | |||
215 | #define HVA_MAX_INSTANCES 16 | ||
216 | #define HVA_MAX_ENCODERS 10 | ||
217 | #define HVA_MAX_FORMATS HVA_MAX_ENCODERS | ||
218 | |||
219 | /** | ||
220 | * struct hva_dev - abstraction for hva entity | ||
221 | * | ||
222 | * @v4l2_dev: V4L2 device | ||
223 | * @vdev: video device | ||
224 | * @pdev: platform device | ||
225 | * @dev: device | ||
226 | * @lock: mutex used for critical sections & V4L2 ops | ||
227 | * serialization | ||
228 | * @m2m_dev: memory-to-memory V4L2 device information | ||
229 | * @instances: opened instances | ||
230 | * @nb_of_instances: number of opened instances | ||
231 | * @instance_id: rolling counter identifying an instance (debug purpose) | ||
232 | * @regs: register io memory access | ||
233 | * @esram_addr: esram address | ||
234 | * @esram_size: esram size | ||
235 | * @clk: hva clock | ||
236 | * @irq_its: status interruption | ||
237 | * @irq_err: error interruption | ||
238 | * @work_queue: work queue to handle the encode jobs | ||
239 | * @protect_mutex: mutex used to lock access of hardware | ||
240 | * @interrupt: completion interrupt | ||
241 | * @ip_version: IP hardware version | ||
242 | * @encoders: registered encoders | ||
243 | * @nb_of_encoders: number of registered encoders | ||
244 | * @pixelformats: supported uncompressed video formats | ||
245 | * @nb_of_pixelformats: number of supported umcompressed video formats | ||
246 | * @streamformats: supported compressed video formats | ||
247 | * @nb_of_streamformats: number of supported compressed video formats | ||
248 | * @sfl_reg: status fifo level register value | ||
249 | * @sts_reg: status register value | ||
250 | * @lmi_err_reg: local memory interface error register value | ||
251 | * @emi_err_reg: external memory interface error register value | ||
252 | * @hec_mif_err_reg: HEC memory interface error register value | ||
253 | */ | ||
254 | struct hva_dev { | ||
255 | struct v4l2_device v4l2_dev; | ||
256 | struct video_device *vdev; | ||
257 | struct platform_device *pdev; | ||
258 | struct device *dev; | ||
259 | /* mutex protecting vb2_queue structure */ | ||
260 | struct mutex lock; | ||
261 | struct v4l2_m2m_dev *m2m_dev; | ||
262 | struct hva_ctx *instances[HVA_MAX_INSTANCES]; | ||
263 | unsigned int nb_of_instances; | ||
264 | unsigned int instance_id; | ||
265 | void __iomem *regs; | ||
266 | u32 esram_addr; | ||
267 | u32 esram_size; | ||
268 | struct clk *clk; | ||
269 | int irq_its; | ||
270 | int irq_err; | ||
271 | struct workqueue_struct *work_queue; | ||
272 | /* mutex protecting hardware access */ | ||
273 | struct mutex protect_mutex; | ||
274 | struct completion interrupt; | ||
275 | unsigned long int ip_version; | ||
276 | const struct hva_enc *encoders[HVA_MAX_ENCODERS]; | ||
277 | u32 nb_of_encoders; | ||
278 | u32 pixelformats[HVA_MAX_FORMATS]; | ||
279 | u32 nb_of_pixelformats; | ||
280 | u32 streamformats[HVA_MAX_FORMATS]; | ||
281 | u32 nb_of_streamformats; | ||
282 | u32 sfl_reg; | ||
283 | u32 sts_reg; | ||
284 | u32 lmi_err_reg; | ||
285 | u32 emi_err_reg; | ||
286 | u32 hec_mif_err_reg; | ||
287 | }; | ||
288 | |||
289 | /** | ||
290 | * struct hva_enc - hva encoder | ||
291 | * | ||
292 | * @name: encoder name | ||
293 | * @streamformat: fourcc code for compressed video format (H.264...) | ||
294 | * @pixelformat: fourcc code for uncompressed video format | ||
295 | * @max_width: maximum width of frame for this encoder | ||
296 | * @max_height: maximum height of frame for this encoder | ||
297 | * @open: open encoder | ||
298 | * @close: close encoder | ||
299 | * @encode: encode a frame (struct hva_frame) in a stream | ||
300 | * (struct hva_stream) | ||
301 | */ | ||
302 | |||
303 | struct hva_enc { | ||
304 | const char *name; | ||
305 | u32 streamformat; | ||
306 | u32 pixelformat; | ||
307 | u32 max_width; | ||
308 | u32 max_height; | ||
309 | int (*open)(struct hva_ctx *ctx); | ||
310 | int (*close)(struct hva_ctx *ctx); | ||
311 | int (*encode)(struct hva_ctx *ctx, struct hva_frame *frame, | ||
312 | struct hva_stream *stream); | ||
313 | }; | ||
314 | |||
315 | #endif /* HVA_H */ | ||
diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index e967fcfdc1d8..44323cb5d287 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c | |||
@@ -1379,7 +1379,7 @@ static void cal_stop_streaming(struct vb2_queue *vq) | |||
1379 | cal_runtime_put(ctx->dev); | 1379 | cal_runtime_put(ctx->dev); |
1380 | } | 1380 | } |
1381 | 1381 | ||
1382 | static struct vb2_ops cal_video_qops = { | 1382 | static const struct vb2_ops cal_video_qops = { |
1383 | .queue_setup = cal_queue_setup, | 1383 | .queue_setup = cal_queue_setup, |
1384 | .buf_prepare = cal_buffer_prepare, | 1384 | .buf_prepare = cal_buffer_prepare, |
1385 | .buf_queue = cal_buffer_queue, | 1385 | .buf_queue = cal_buffer_queue, |
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 55a1458ac783..0189f7f7cb03 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c | |||
@@ -1878,7 +1878,7 @@ static void vpe_stop_streaming(struct vb2_queue *q) | |||
1878 | vpdma_dump_regs(ctx->dev->vpdma); | 1878 | vpdma_dump_regs(ctx->dev->vpdma); |
1879 | } | 1879 | } |
1880 | 1880 | ||
1881 | static struct vb2_ops vpe_qops = { | 1881 | static const struct vb2_ops vpe_qops = { |
1882 | .queue_setup = vpe_queue_setup, | 1882 | .queue_setup = vpe_queue_setup, |
1883 | .buf_prepare = vpe_buf_prepare, | 1883 | .buf_prepare = vpe_buf_prepare, |
1884 | .buf_queue = vpe_buf_queue, | 1884 | .buf_queue = vpe_buf_queue, |
diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index cd0ff4a66fdc..a98f679bd88d 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c | |||
@@ -815,7 +815,7 @@ static void vim2m_stop_streaming(struct vb2_queue *q) | |||
815 | } | 815 | } |
816 | } | 816 | } |
817 | 817 | ||
818 | static struct vb2_ops vim2m_qops = { | 818 | static const struct vb2_ops vim2m_qops = { |
819 | .queue_setup = vim2m_queue_setup, | 819 | .queue_setup = vim2m_queue_setup, |
820 | .buf_prepare = vim2m_buf_prepare, | 820 | .buf_prepare = vim2m_buf_prepare, |
821 | .buf_queue = vim2m_buf_queue, | 821 | .buf_queue = vim2m_buf_queue, |
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 7f937136c3f5..5464fefbaab9 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c | |||
@@ -163,38 +163,38 @@ const struct v4l2_rect vivid_max_rect = { | |||
163 | 163 | ||
164 | static const u8 vivid_hdmi_edid[256] = { | 164 | static const u8 vivid_hdmi_edid[256] = { |
165 | 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, | 165 | 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, |
166 | 0x63, 0x3a, 0xaa, 0x55, 0x00, 0x00, 0x00, 0x00, | 166 | 0x31, 0xd8, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, |
167 | 0x0a, 0x18, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78, | 167 | 0x22, 0x1a, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78, |
168 | 0x0e, 0x00, 0xb2, 0xa0, 0x57, 0x49, 0x9b, 0x26, | 168 | 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, |
169 | 0x10, 0x48, 0x4f, 0x2f, 0xcf, 0x00, 0x31, 0x59, | 169 | 0x0f, 0x50, 0x54, 0x2f, 0xcf, 0x00, 0x31, 0x59, |
170 | 0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40, | 170 | 0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40, |
171 | 0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x02, 0x3a, | 171 | 0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x08, 0xe8, |
172 | 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, | 172 | 0x00, 0x30, 0xf2, 0x70, 0x5a, 0x80, 0xb0, 0x58, |
173 | 0x46, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00, 0x1e, | 173 | 0x8a, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e, |
174 | 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18, | 174 | 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18, |
175 | 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, | 175 | 0x87, 0x3c, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, |
176 | 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 'v', | 176 | 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x76, |
177 | '4', 'l', '2', '-', 'h', 'd', 'm', 'i', | 177 | 0x69, 0x76, 0x69, 0x64, 0x0a, 0x20, 0x20, 0x20, |
178 | 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x10, | 178 | 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x10, |
179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, | 180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7b, |
181 | 181 | ||
182 | 0x02, 0x03, 0x1a, 0xc0, 0x48, 0xa2, 0x10, 0x04, | 182 | 0x02, 0x03, 0x3f, 0xf0, 0x51, 0x61, 0x60, 0x5f, |
183 | 0x02, 0x01, 0x21, 0x14, 0x13, 0x23, 0x09, 0x07, | 183 | 0x5e, 0x5d, 0x10, 0x1f, 0x04, 0x13, 0x22, 0x21, |
184 | 0x07, 0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, 0xe2, | 184 | 0x20, 0x05, 0x14, 0x02, 0x11, 0x01, 0x23, 0x09, |
185 | 0x00, 0x2a, 0x01, 0x1d, 0x00, 0x80, 0x51, 0xd0, | 185 | 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x6d, 0x03, |
186 | 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0x00, 0x00, | 186 | 0x0c, 0x00, 0x10, 0x00, 0x00, 0x78, 0x21, 0x00, |
187 | 0x00, 0x00, 0x00, 0x1e, 0x8c, 0x0a, 0xd0, 0x8a, | 187 | 0x60, 0x01, 0x02, 0x03, 0x67, 0xd8, 0x5d, 0xc4, |
188 | 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, | 188 | 0x01, 0x78, 0x00, 0x00, 0xe2, 0x00, 0xea, 0xe3, |
189 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, | 189 | 0x05, 0x00, 0x00, 0xe3, 0x06, 0x01, 0x00, 0x4d, |
190 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 190 | 0xd0, 0x00, 0xa0, 0xf0, 0x70, 0x3e, 0x80, 0x30, |
191 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 191 | 0x20, 0x35, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, |
192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 192 | 0x1e, 0x1a, 0x36, 0x80, 0xa0, 0x70, 0x38, 0x1f, |
193 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 193 | 0x40, 0x30, 0x20, 0x35, 0x00, 0xc0, 0x1c, 0x32, |
194 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 194 | 0x00, 0x00, 0x1a, 0x1a, 0x1d, 0x00, 0x80, 0x51, |
195 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 195 | 0xd0, 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0xc0, |
196 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 196 | 0x1c, 0x32, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, |
197 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7 | 197 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, |
198 | }; | 198 | }; |
199 | 199 | ||
200 | static int vidioc_querycap(struct file *file, void *priv, | 200 | static int vidioc_querycap(struct file *file, void *priv, |
@@ -839,6 +839,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
839 | dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR | | 839 | dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR | |
840 | V4L2_CAP_READWRITE; | 840 | V4L2_CAP_READWRITE; |
841 | 841 | ||
842 | ret = -ENOMEM; | ||
842 | /* initialize the test pattern generator */ | 843 | /* initialize the test pattern generator */ |
843 | tpg_init(&dev->tpg, 640, 360); | 844 | tpg_init(&dev->tpg, 640, 360); |
844 | if (tpg_alloc(&dev->tpg, MAX_ZOOM * MAX_WIDTH)) | 845 | if (tpg_alloc(&dev->tpg, MAX_ZOOM * MAX_WIDTH)) |
@@ -1033,8 +1034,10 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1033 | */ | 1034 | */ |
1034 | dev->cec_workqueue = | 1035 | dev->cec_workqueue = |
1035 | alloc_ordered_workqueue("vivid-%03d-cec", WQ_MEM_RECLAIM, inst); | 1036 | alloc_ordered_workqueue("vivid-%03d-cec", WQ_MEM_RECLAIM, inst); |
1036 | if (!dev->cec_workqueue) | 1037 | if (!dev->cec_workqueue) { |
1038 | ret = -ENOMEM; | ||
1037 | goto unreg_dev; | 1039 | goto unreg_dev; |
1040 | } | ||
1038 | 1041 | ||
1039 | /* start creating the vb2 queues */ | 1042 | /* start creating the vb2 queues */ |
1040 | if (dev->has_vid_cap) { | 1043 | if (dev->has_vid_cap) { |
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index b98089c95ef5..aceb38d9f7e7 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c | |||
@@ -761,7 +761,7 @@ static const char * const vivid_ctrl_ycbcr_enc_strings[] = { | |||
761 | "Rec. 709", | 761 | "Rec. 709", |
762 | "xvYCC 601", | 762 | "xvYCC 601", |
763 | "xvYCC 709", | 763 | "xvYCC 709", |
764 | "sYCC", | 764 | "", |
765 | "BT.2020", | 765 | "BT.2020", |
766 | "BT.2020 Constant Luminance", | 766 | "BT.2020 Constant Luminance", |
767 | "SMPTE 240M", | 767 | "SMPTE 240M", |
@@ -773,6 +773,7 @@ static const struct v4l2_ctrl_config vivid_ctrl_ycbcr_enc = { | |||
773 | .id = VIVID_CID_YCBCR_ENC, | 773 | .id = VIVID_CID_YCBCR_ENC, |
774 | .name = "Y'CbCr Encoding", | 774 | .name = "Y'CbCr Encoding", |
775 | .type = V4L2_CTRL_TYPE_MENU, | 775 | .type = V4L2_CTRL_TYPE_MENU, |
776 | .menu_skip_mask = 1 << 5, | ||
776 | .max = ARRAY_SIZE(vivid_ctrl_ycbcr_enc_strings) - 2, | 777 | .max = ARRAY_SIZE(vivid_ctrl_ycbcr_enc_strings) - 2, |
777 | .qmenu = vivid_ctrl_ycbcr_enc_strings, | 778 | .qmenu = vivid_ctrl_ycbcr_enc_strings, |
778 | }; | 779 | }; |
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index d404a7ce33a4..d5c84ecf2027 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c | |||
@@ -823,7 +823,7 @@ int vivid_vid_cap_g_selection(struct file *file, void *priv, | |||
823 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 823 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
824 | return -EINVAL; | 824 | return -EINVAL; |
825 | if (vivid_is_webcam(dev)) | 825 | if (vivid_is_webcam(dev)) |
826 | return -EINVAL; | 826 | return -ENODATA; |
827 | 827 | ||
828 | sel->r.left = sel->r.top = 0; | 828 | sel->r.left = sel->r.top = 0; |
829 | switch (sel->target) { | 829 | switch (sel->target) { |
@@ -872,7 +872,7 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection | |||
872 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 872 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
873 | return -EINVAL; | 873 | return -EINVAL; |
874 | if (vivid_is_webcam(dev)) | 874 | if (vivid_is_webcam(dev)) |
875 | return -EINVAL; | 875 | return -ENODATA; |
876 | 876 | ||
877 | switch (s->target) { | 877 | switch (s->target) { |
878 | case V4L2_SEL_TGT_CROP: | 878 | case V4L2_SEL_TGT_CROP: |
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 06a2ec7e5ad4..b23fa879a9aa 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h | |||
@@ -53,6 +53,7 @@ struct vsp1_uds; | |||
53 | 53 | ||
54 | struct vsp1_device_info { | 54 | struct vsp1_device_info { |
55 | u32 version; | 55 | u32 version; |
56 | const char *model; | ||
56 | unsigned int gen; | 57 | unsigned int gen; |
57 | unsigned int features; | 58 | unsigned int features; |
58 | unsigned int rpf_count; | 59 | unsigned int rpf_count; |
@@ -65,6 +66,7 @@ struct vsp1_device_info { | |||
65 | struct vsp1_device { | 66 | struct vsp1_device { |
66 | struct device *dev; | 67 | struct device *dev; |
67 | const struct vsp1_device_info *info; | 68 | const struct vsp1_device_info *info; |
69 | u32 version; | ||
68 | 70 | ||
69 | void __iomem *mmio; | 71 | void __iomem *mmio; |
70 | struct rcar_fcp_device *fcp; | 72 | struct rcar_fcp_device *fcp; |
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index 8268b87727a7..ee8355c28f94 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c | |||
@@ -142,10 +142,15 @@ static int bru_set_format(struct v4l2_subdev *subdev, | |||
142 | struct vsp1_bru *bru = to_bru(subdev); | 142 | struct vsp1_bru *bru = to_bru(subdev); |
143 | struct v4l2_subdev_pad_config *config; | 143 | struct v4l2_subdev_pad_config *config; |
144 | struct v4l2_mbus_framefmt *format; | 144 | struct v4l2_mbus_framefmt *format; |
145 | int ret = 0; | ||
146 | |||
147 | mutex_lock(&bru->entity.lock); | ||
145 | 148 | ||
146 | config = vsp1_entity_get_pad_config(&bru->entity, cfg, fmt->which); | 149 | config = vsp1_entity_get_pad_config(&bru->entity, cfg, fmt->which); |
147 | if (!config) | 150 | if (!config) { |
148 | return -EINVAL; | 151 | ret = -EINVAL; |
152 | goto done; | ||
153 | } | ||
149 | 154 | ||
150 | bru_try_format(bru, config, fmt->pad, &fmt->format); | 155 | bru_try_format(bru, config, fmt->pad, &fmt->format); |
151 | 156 | ||
@@ -174,7 +179,9 @@ static int bru_set_format(struct v4l2_subdev *subdev, | |||
174 | } | 179 | } |
175 | } | 180 | } |
176 | 181 | ||
177 | return 0; | 182 | done: |
183 | mutex_unlock(&bru->entity.lock); | ||
184 | return ret; | ||
178 | } | 185 | } |
179 | 186 | ||
180 | static int bru_get_selection(struct v4l2_subdev *subdev, | 187 | static int bru_get_selection(struct v4l2_subdev *subdev, |
@@ -201,7 +208,9 @@ static int bru_get_selection(struct v4l2_subdev *subdev, | |||
201 | if (!config) | 208 | if (!config) |
202 | return -EINVAL; | 209 | return -EINVAL; |
203 | 210 | ||
211 | mutex_lock(&bru->entity.lock); | ||
204 | sel->r = *bru_get_compose(bru, config, sel->pad); | 212 | sel->r = *bru_get_compose(bru, config, sel->pad); |
213 | mutex_unlock(&bru->entity.lock); | ||
205 | return 0; | 214 | return 0; |
206 | 215 | ||
207 | default: | 216 | default: |
@@ -217,6 +226,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev, | |||
217 | struct v4l2_subdev_pad_config *config; | 226 | struct v4l2_subdev_pad_config *config; |
218 | struct v4l2_mbus_framefmt *format; | 227 | struct v4l2_mbus_framefmt *format; |
219 | struct v4l2_rect *compose; | 228 | struct v4l2_rect *compose; |
229 | int ret = 0; | ||
220 | 230 | ||
221 | if (sel->pad == bru->entity.source_pad) | 231 | if (sel->pad == bru->entity.source_pad) |
222 | return -EINVAL; | 232 | return -EINVAL; |
@@ -224,11 +234,16 @@ static int bru_set_selection(struct v4l2_subdev *subdev, | |||
224 | if (sel->target != V4L2_SEL_TGT_COMPOSE) | 234 | if (sel->target != V4L2_SEL_TGT_COMPOSE) |
225 | return -EINVAL; | 235 | return -EINVAL; |
226 | 236 | ||
237 | mutex_lock(&bru->entity.lock); | ||
238 | |||
227 | config = vsp1_entity_get_pad_config(&bru->entity, cfg, sel->which); | 239 | config = vsp1_entity_get_pad_config(&bru->entity, cfg, sel->which); |
228 | if (!config) | 240 | if (!config) { |
229 | return -EINVAL; | 241 | ret = -EINVAL; |
242 | goto done; | ||
243 | } | ||
230 | 244 | ||
231 | /* The compose rectangle top left corner must be inside the output | 245 | /* |
246 | * The compose rectangle top left corner must be inside the output | ||
232 | * frame. | 247 | * frame. |
233 | */ | 248 | */ |
234 | format = vsp1_entity_get_pad_format(&bru->entity, config, | 249 | format = vsp1_entity_get_pad_format(&bru->entity, config, |
@@ -246,7 +261,9 @@ static int bru_set_selection(struct v4l2_subdev *subdev, | |||
246 | compose = bru_get_compose(bru, config, sel->pad); | 261 | compose = bru_get_compose(bru, config, sel->pad); |
247 | *compose = sel->r; | 262 | *compose = sel->r; |
248 | 263 | ||
249 | return 0; | 264 | done: |
265 | mutex_unlock(&bru->entity.lock); | ||
266 | return ret; | ||
250 | } | 267 | } |
251 | 268 | ||
252 | static const struct v4l2_subdev_pad_ops bru_pad_ops = { | 269 | static const struct v4l2_subdev_pad_ops bru_pad_ops = { |
@@ -269,14 +286,15 @@ static const struct v4l2_subdev_ops bru_ops = { | |||
269 | 286 | ||
270 | static void bru_configure(struct vsp1_entity *entity, | 287 | static void bru_configure(struct vsp1_entity *entity, |
271 | struct vsp1_pipeline *pipe, | 288 | struct vsp1_pipeline *pipe, |
272 | struct vsp1_dl_list *dl, bool full) | 289 | struct vsp1_dl_list *dl, |
290 | enum vsp1_entity_params params) | ||
273 | { | 291 | { |
274 | struct vsp1_bru *bru = to_bru(&entity->subdev); | 292 | struct vsp1_bru *bru = to_bru(&entity->subdev); |
275 | struct v4l2_mbus_framefmt *format; | 293 | struct v4l2_mbus_framefmt *format; |
276 | unsigned int flags; | 294 | unsigned int flags; |
277 | unsigned int i; | 295 | unsigned int i; |
278 | 296 | ||
279 | if (!full) | 297 | if (params != VSP1_ENTITY_PARAMS_INIT) |
280 | return; | 298 | return; |
281 | 299 | ||
282 | format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config, | 300 | format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config, |
diff --git a/drivers/media/platform/vsp1/vsp1_clu.c b/drivers/media/platform/vsp1/vsp1_clu.c index b63d2dbe5ea3..f2fb26e5ab4e 100644 --- a/drivers/media/platform/vsp1/vsp1_clu.c +++ b/drivers/media/platform/vsp1/vsp1_clu.c | |||
@@ -148,10 +148,15 @@ static int clu_set_format(struct v4l2_subdev *subdev, | |||
148 | struct vsp1_clu *clu = to_clu(subdev); | 148 | struct vsp1_clu *clu = to_clu(subdev); |
149 | struct v4l2_subdev_pad_config *config; | 149 | struct v4l2_subdev_pad_config *config; |
150 | struct v4l2_mbus_framefmt *format; | 150 | struct v4l2_mbus_framefmt *format; |
151 | int ret = 0; | ||
152 | |||
153 | mutex_lock(&clu->entity.lock); | ||
151 | 154 | ||
152 | config = vsp1_entity_get_pad_config(&clu->entity, cfg, fmt->which); | 155 | config = vsp1_entity_get_pad_config(&clu->entity, cfg, fmt->which); |
153 | if (!config) | 156 | if (!config) { |
154 | return -EINVAL; | 157 | ret = -EINVAL; |
158 | goto done; | ||
159 | } | ||
155 | 160 | ||
156 | /* Default to YUV if the requested format is not supported. */ | 161 | /* Default to YUV if the requested format is not supported. */ |
157 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && | 162 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && |
@@ -164,7 +169,7 @@ static int clu_set_format(struct v4l2_subdev *subdev, | |||
164 | if (fmt->pad == CLU_PAD_SOURCE) { | 169 | if (fmt->pad == CLU_PAD_SOURCE) { |
165 | /* The CLU output format can't be modified. */ | 170 | /* The CLU output format can't be modified. */ |
166 | fmt->format = *format; | 171 | fmt->format = *format; |
167 | return 0; | 172 | goto done; |
168 | } | 173 | } |
169 | 174 | ||
170 | format->code = fmt->format.code; | 175 | format->code = fmt->format.code; |
@@ -182,7 +187,9 @@ static int clu_set_format(struct v4l2_subdev *subdev, | |||
182 | CLU_PAD_SOURCE); | 187 | CLU_PAD_SOURCE); |
183 | *format = fmt->format; | 188 | *format = fmt->format; |
184 | 189 | ||
185 | return 0; | 190 | done: |
191 | mutex_unlock(&clu->entity.lock); | ||
192 | return ret; | ||
186 | } | 193 | } |
187 | 194 | ||
188 | /* ----------------------------------------------------------------------------- | 195 | /* ----------------------------------------------------------------------------- |
@@ -207,42 +214,51 @@ static const struct v4l2_subdev_ops clu_ops = { | |||
207 | 214 | ||
208 | static void clu_configure(struct vsp1_entity *entity, | 215 | static void clu_configure(struct vsp1_entity *entity, |
209 | struct vsp1_pipeline *pipe, | 216 | struct vsp1_pipeline *pipe, |
210 | struct vsp1_dl_list *dl, bool full) | 217 | struct vsp1_dl_list *dl, |
218 | enum vsp1_entity_params params) | ||
211 | { | 219 | { |
212 | struct vsp1_clu *clu = to_clu(&entity->subdev); | 220 | struct vsp1_clu *clu = to_clu(&entity->subdev); |
213 | struct vsp1_dl_body *dlb; | 221 | struct vsp1_dl_body *dlb; |
214 | unsigned long flags; | 222 | unsigned long flags; |
215 | u32 ctrl = VI6_CLU_CTRL_AAI | VI6_CLU_CTRL_MVS | VI6_CLU_CTRL_EN; | 223 | u32 ctrl = VI6_CLU_CTRL_AAI | VI6_CLU_CTRL_MVS | VI6_CLU_CTRL_EN; |
216 | 224 | ||
217 | /* The format can't be changed during streaming, only verify it at | 225 | switch (params) { |
218 | * stream start and store the information internally for future partial | 226 | case VSP1_ENTITY_PARAMS_INIT: { |
219 | * reconfiguration calls. | 227 | /* |
220 | */ | 228 | * The format can't be changed during streaming, only verify it |
221 | if (full) { | 229 | * at setup time and store the information internally for future |
230 | * runtime configuration calls. | ||
231 | */ | ||
222 | struct v4l2_mbus_framefmt *format; | 232 | struct v4l2_mbus_framefmt *format; |
223 | 233 | ||
224 | format = vsp1_entity_get_pad_format(&clu->entity, | 234 | format = vsp1_entity_get_pad_format(&clu->entity, |
225 | clu->entity.config, | 235 | clu->entity.config, |
226 | CLU_PAD_SINK); | 236 | CLU_PAD_SINK); |
227 | clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32; | 237 | clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32; |
228 | return; | 238 | break; |
229 | } | 239 | } |
230 | 240 | ||
231 | /* 2D mode can only be used with the YCbCr pixel encoding. */ | 241 | case VSP1_ENTITY_PARAMS_PARTITION: |
232 | if (clu->mode == V4L2_CID_VSP1_CLU_MODE_2D && clu->yuv_mode) | 242 | break; |
233 | ctrl |= VI6_CLU_CTRL_AX1I_2D | VI6_CLU_CTRL_AX2I_2D | 243 | |
234 | | VI6_CLU_CTRL_OS0_2D | VI6_CLU_CTRL_OS1_2D | 244 | case VSP1_ENTITY_PARAMS_RUNTIME: |
235 | | VI6_CLU_CTRL_OS2_2D | VI6_CLU_CTRL_M2D; | 245 | /* 2D mode can only be used with the YCbCr pixel encoding. */ |
246 | if (clu->mode == V4L2_CID_VSP1_CLU_MODE_2D && clu->yuv_mode) | ||
247 | ctrl |= VI6_CLU_CTRL_AX1I_2D | VI6_CLU_CTRL_AX2I_2D | ||
248 | | VI6_CLU_CTRL_OS0_2D | VI6_CLU_CTRL_OS1_2D | ||
249 | | VI6_CLU_CTRL_OS2_2D | VI6_CLU_CTRL_M2D; | ||
236 | 250 | ||
237 | vsp1_clu_write(clu, dl, VI6_CLU_CTRL, ctrl); | 251 | vsp1_clu_write(clu, dl, VI6_CLU_CTRL, ctrl); |
238 | 252 | ||
239 | spin_lock_irqsave(&clu->lock, flags); | 253 | spin_lock_irqsave(&clu->lock, flags); |
240 | dlb = clu->clu; | 254 | dlb = clu->clu; |
241 | clu->clu = NULL; | 255 | clu->clu = NULL; |
242 | spin_unlock_irqrestore(&clu->lock, flags); | 256 | spin_unlock_irqrestore(&clu->lock, flags); |
243 | 257 | ||
244 | if (dlb) | 258 | if (dlb) |
245 | vsp1_dl_list_add_fragment(dl, dlb); | 259 | vsp1_dl_list_add_fragment(dl, dlb); |
260 | break; | ||
261 | } | ||
246 | } | 262 | } |
247 | 263 | ||
248 | static const struct vsp1_entity_operations clu_entity_ops = { | 264 | static const struct vsp1_entity_operations clu_entity_ops = { |
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index 37c3518aa2a8..ad545aff4e35 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include "vsp1_dl.h" | 21 | #include "vsp1_dl.h" |
22 | 22 | ||
23 | #define VSP1_DL_NUM_ENTRIES 256 | 23 | #define VSP1_DL_NUM_ENTRIES 256 |
24 | #define VSP1_DL_NUM_LISTS 3 | ||
25 | 24 | ||
26 | #define VSP1_DLH_INT_ENABLE (1 << 1) | 25 | #define VSP1_DLH_INT_ENABLE (1 << 1) |
27 | #define VSP1_DLH_AUTO_START (1 << 0) | 26 | #define VSP1_DLH_AUTO_START (1 << 0) |
@@ -71,6 +70,7 @@ struct vsp1_dl_body { | |||
71 | * @dma: DMA address for the header | 70 | * @dma: DMA address for the header |
72 | * @body0: first display list body | 71 | * @body0: first display list body |
73 | * @fragments: list of extra display list bodies | 72 | * @fragments: list of extra display list bodies |
73 | * @chain: entry in the display list partition chain | ||
74 | */ | 74 | */ |
75 | struct vsp1_dl_list { | 75 | struct vsp1_dl_list { |
76 | struct list_head list; | 76 | struct list_head list; |
@@ -81,6 +81,9 @@ struct vsp1_dl_list { | |||
81 | 81 | ||
82 | struct vsp1_dl_body body0; | 82 | struct vsp1_dl_body body0; |
83 | struct list_head fragments; | 83 | struct list_head fragments; |
84 | |||
85 | bool has_chain; | ||
86 | struct list_head chain; | ||
84 | }; | 87 | }; |
85 | 88 | ||
86 | enum vsp1_dl_mode { | 89 | enum vsp1_dl_mode { |
@@ -262,7 +265,6 @@ static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm) | |||
262 | 265 | ||
263 | memset(dl->header, 0, sizeof(*dl->header)); | 266 | memset(dl->header, 0, sizeof(*dl->header)); |
264 | dl->header->lists[0].addr = dl->body0.dma; | 267 | dl->header->lists[0].addr = dl->body0.dma; |
265 | dl->header->flags = VSP1_DLH_INT_ENABLE; | ||
266 | } | 268 | } |
267 | 269 | ||
268 | return dl; | 270 | return dl; |
@@ -293,6 +295,12 @@ struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm) | |||
293 | if (!list_empty(&dlm->free)) { | 295 | if (!list_empty(&dlm->free)) { |
294 | dl = list_first_entry(&dlm->free, struct vsp1_dl_list, list); | 296 | dl = list_first_entry(&dlm->free, struct vsp1_dl_list, list); |
295 | list_del(&dl->list); | 297 | list_del(&dl->list); |
298 | |||
299 | /* | ||
300 | * The display list chain must be initialised to ensure every | ||
301 | * display list can assert list_empty() if it is not in a chain. | ||
302 | */ | ||
303 | INIT_LIST_HEAD(&dl->chain); | ||
296 | } | 304 | } |
297 | 305 | ||
298 | spin_unlock_irqrestore(&dlm->lock, flags); | 306 | spin_unlock_irqrestore(&dlm->lock, flags); |
@@ -303,10 +311,24 @@ struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm) | |||
303 | /* This function must be called with the display list manager lock held.*/ | 311 | /* This function must be called with the display list manager lock held.*/ |
304 | static void __vsp1_dl_list_put(struct vsp1_dl_list *dl) | 312 | static void __vsp1_dl_list_put(struct vsp1_dl_list *dl) |
305 | { | 313 | { |
314 | struct vsp1_dl_list *dl_child; | ||
315 | |||
306 | if (!dl) | 316 | if (!dl) |
307 | return; | 317 | return; |
308 | 318 | ||
309 | /* We can't free fragments here as DMA memory can only be freed in | 319 | /* |
320 | * Release any linked display-lists which were chained for a single | ||
321 | * hardware operation. | ||
322 | */ | ||
323 | if (dl->has_chain) { | ||
324 | list_for_each_entry(dl_child, &dl->chain, chain) | ||
325 | __vsp1_dl_list_put(dl_child); | ||
326 | } | ||
327 | |||
328 | dl->has_chain = false; | ||
329 | |||
330 | /* | ||
331 | * We can't free fragments here as DMA memory can only be freed in | ||
310 | * interruptible context. Move all fragments to the display list | 332 | * interruptible context. Move all fragments to the display list |
311 | * manager's list of fragments to be freed, they will be | 333 | * manager's list of fragments to be freed, they will be |
312 | * garbage-collected by the work queue. | 334 | * garbage-collected by the work queue. |
@@ -383,6 +405,76 @@ int vsp1_dl_list_add_fragment(struct vsp1_dl_list *dl, | |||
383 | return 0; | 405 | return 0; |
384 | } | 406 | } |
385 | 407 | ||
408 | /** | ||
409 | * vsp1_dl_list_add_chain - Add a display list to a chain | ||
410 | * @head: The head display list | ||
411 | * @dl: The new display list | ||
412 | * | ||
413 | * Add a display list to an existing display list chain. The chained lists | ||
414 | * will be automatically processed by the hardware without intervention from | ||
415 | * the CPU. A display list end interrupt will only complete after the last | ||
416 | * display list in the chain has completed processing. | ||
417 | * | ||
418 | * Adding a display list to a chain passes ownership of the display list to | ||
419 | * the head display list item. The chain is released when the head dl item is | ||
420 | * put back with __vsp1_dl_list_put(). | ||
421 | * | ||
422 | * Chained display lists are only usable in header mode. Attempts to add a | ||
423 | * display list to a chain in header-less mode will return an error. | ||
424 | */ | ||
425 | int vsp1_dl_list_add_chain(struct vsp1_dl_list *head, | ||
426 | struct vsp1_dl_list *dl) | ||
427 | { | ||
428 | /* Chained lists are only available in header mode. */ | ||
429 | if (head->dlm->mode != VSP1_DL_MODE_HEADER) | ||
430 | return -EINVAL; | ||
431 | |||
432 | head->has_chain = true; | ||
433 | list_add_tail(&dl->chain, &head->chain); | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static void vsp1_dl_list_fill_header(struct vsp1_dl_list *dl, bool is_last) | ||
438 | { | ||
439 | struct vsp1_dl_header_list *hdr = dl->header->lists; | ||
440 | struct vsp1_dl_body *dlb; | ||
441 | unsigned int num_lists = 0; | ||
442 | |||
443 | /* | ||
444 | * Fill the header with the display list bodies addresses and sizes. The | ||
445 | * address of the first body has already been filled when the display | ||
446 | * list was allocated. | ||
447 | */ | ||
448 | |||
449 | hdr->num_bytes = dl->body0.num_entries | ||
450 | * sizeof(*dl->header->lists); | ||
451 | |||
452 | list_for_each_entry(dlb, &dl->fragments, list) { | ||
453 | num_lists++; | ||
454 | hdr++; | ||
455 | |||
456 | hdr->addr = dlb->dma; | ||
457 | hdr->num_bytes = dlb->num_entries | ||
458 | * sizeof(*dl->header->lists); | ||
459 | } | ||
460 | |||
461 | dl->header->num_lists = num_lists; | ||
462 | |||
463 | /* | ||
464 | * If this display list's chain is not empty, we are on a list, where | ||
465 | * the next item in the list is the display list entity which should be | ||
466 | * automatically queued by the hardware. | ||
467 | */ | ||
468 | if (!list_empty(&dl->chain) && !is_last) { | ||
469 | struct vsp1_dl_list *next = list_next_entry(dl, chain); | ||
470 | |||
471 | dl->header->next_header = next->dma; | ||
472 | dl->header->flags = VSP1_DLH_AUTO_START; | ||
473 | } else { | ||
474 | dl->header->flags = VSP1_DLH_INT_ENABLE; | ||
475 | } | ||
476 | } | ||
477 | |||
386 | void vsp1_dl_list_commit(struct vsp1_dl_list *dl) | 478 | void vsp1_dl_list_commit(struct vsp1_dl_list *dl) |
387 | { | 479 | { |
388 | struct vsp1_dl_manager *dlm = dl->dlm; | 480 | struct vsp1_dl_manager *dlm = dl->dlm; |
@@ -393,30 +485,26 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl) | |||
393 | spin_lock_irqsave(&dlm->lock, flags); | 485 | spin_lock_irqsave(&dlm->lock, flags); |
394 | 486 | ||
395 | if (dl->dlm->mode == VSP1_DL_MODE_HEADER) { | 487 | if (dl->dlm->mode == VSP1_DL_MODE_HEADER) { |
396 | struct vsp1_dl_header_list *hdr = dl->header->lists; | 488 | struct vsp1_dl_list *dl_child; |
397 | struct vsp1_dl_body *dlb; | ||
398 | unsigned int num_lists = 0; | ||
399 | 489 | ||
400 | /* Fill the header with the display list bodies addresses and | 490 | /* |
401 | * sizes. The address of the first body has already been filled | ||
402 | * when the display list was allocated. | ||
403 | * | ||
404 | * In header mode the caller guarantees that the hardware is | 491 | * In header mode the caller guarantees that the hardware is |
405 | * idle at this point. | 492 | * idle at this point. |
406 | */ | 493 | */ |
407 | hdr->num_bytes = dl->body0.num_entries | ||
408 | * sizeof(*dl->header->lists); | ||
409 | 494 | ||
410 | list_for_each_entry(dlb, &dl->fragments, list) { | 495 | /* Fill the header for the head and chained display lists. */ |
411 | num_lists++; | 496 | vsp1_dl_list_fill_header(dl, list_empty(&dl->chain)); |
412 | hdr++; | ||
413 | 497 | ||
414 | hdr->addr = dlb->dma; | 498 | list_for_each_entry(dl_child, &dl->chain, chain) { |
415 | hdr->num_bytes = dlb->num_entries | 499 | bool last = list_is_last(&dl_child->chain, &dl->chain); |
416 | * sizeof(*dl->header->lists); | 500 | |
501 | vsp1_dl_list_fill_header(dl_child, last); | ||
417 | } | 502 | } |
418 | 503 | ||
419 | dl->header->num_lists = num_lists; | 504 | /* |
505 | * Commit the head display list to hardware. Chained headers | ||
506 | * will auto-start. | ||
507 | */ | ||
420 | vsp1_write(vsp1, VI6_DL_HDR_ADDR(dlm->index), dl->dma); | 508 | vsp1_write(vsp1, VI6_DL_HDR_ADDR(dlm->index), dl->dma); |
421 | 509 | ||
422 | dlm->active = dl; | 510 | dlm->active = dl; |
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h index de387cd4d745..7131aa3c5978 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.h +++ b/drivers/media/platform/vsp1/vsp1_dl.h | |||
@@ -41,5 +41,6 @@ void vsp1_dl_fragment_free(struct vsp1_dl_body *dlb); | |||
41 | void vsp1_dl_fragment_write(struct vsp1_dl_body *dlb, u32 reg, u32 data); | 41 | void vsp1_dl_fragment_write(struct vsp1_dl_body *dlb, u32 reg, u32 data); |
42 | int vsp1_dl_list_add_fragment(struct vsp1_dl_list *dl, | 42 | int vsp1_dl_list_add_fragment(struct vsp1_dl_list *dl, |
43 | struct vsp1_dl_body *dlb); | 43 | struct vsp1_dl_body *dlb); |
44 | int vsp1_dl_list_add_chain(struct vsp1_dl_list *head, struct vsp1_dl_list *dl); | ||
44 | 45 | ||
45 | #endif /* __VSP1_DL_H__ */ | 46 | #endif /* __VSP1_DL_H__ */ |
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index fe9665e57b3b..cd209dccff1b 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c | |||
@@ -276,17 +276,18 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, | |||
276 | } | 276 | } |
277 | 277 | ||
278 | dev_dbg(vsp1->dev, | 278 | dev_dbg(vsp1->dev, |
279 | "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad } zpos %u\n", | 279 | "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad, %pad } zpos %u\n", |
280 | __func__, rpf_index, | 280 | __func__, rpf_index, |
281 | cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height, | 281 | cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height, |
282 | cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height, | 282 | cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height, |
283 | cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1], | 283 | cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1], |
284 | cfg->zpos); | 284 | &cfg->mem[2], cfg->zpos); |
285 | 285 | ||
286 | /* Store the format, stride, memory buffer address, crop and compose | 286 | /* |
287 | * Store the format, stride, memory buffer address, crop and compose | ||
287 | * rectangles and Z-order position and for the input. | 288 | * rectangles and Z-order position and for the input. |
288 | */ | 289 | */ |
289 | fmtinfo = vsp1_get_format_info(cfg->pixelformat); | 290 | fmtinfo = vsp1_get_format_info(vsp1, cfg->pixelformat); |
290 | if (!fmtinfo) { | 291 | if (!fmtinfo) { |
291 | dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n", | 292 | dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n", |
292 | cfg->pixelformat); | 293 | cfg->pixelformat); |
@@ -301,7 +302,7 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, | |||
301 | 302 | ||
302 | rpf->mem.addr[0] = cfg->mem[0]; | 303 | rpf->mem.addr[0] = cfg->mem[0]; |
303 | rpf->mem.addr[1] = cfg->mem[1]; | 304 | rpf->mem.addr[1] = cfg->mem[1]; |
304 | rpf->mem.addr[2] = 0; | 305 | rpf->mem.addr[2] = cfg->mem[2]; |
305 | 306 | ||
306 | vsp1->drm->inputs[rpf_index].crop = cfg->src; | 307 | vsp1->drm->inputs[rpf_index].crop = cfg->src; |
307 | vsp1->drm->inputs[rpf_index].compose = cfg->dst; | 308 | vsp1->drm->inputs[rpf_index].compose = cfg->dst; |
@@ -492,16 +493,13 @@ void vsp1_du_atomic_flush(struct device *dev) | |||
492 | vsp1_entity_route_setup(entity, pipe->dl); | 493 | vsp1_entity_route_setup(entity, pipe->dl); |
493 | 494 | ||
494 | if (entity->ops->configure) { | 495 | if (entity->ops->configure) { |
495 | entity->ops->configure(entity, pipe, pipe->dl, true); | 496 | entity->ops->configure(entity, pipe, pipe->dl, |
496 | entity->ops->configure(entity, pipe, pipe->dl, false); | 497 | VSP1_ENTITY_PARAMS_INIT); |
498 | entity->ops->configure(entity, pipe, pipe->dl, | ||
499 | VSP1_ENTITY_PARAMS_RUNTIME); | ||
500 | entity->ops->configure(entity, pipe, pipe->dl, | ||
501 | VSP1_ENTITY_PARAMS_PARTITION); | ||
497 | } | 502 | } |
498 | |||
499 | /* The memory buffer address must be applied after configuring | ||
500 | * the RPF to make sure the crop offset are computed. | ||
501 | */ | ||
502 | if (entity->type == VSP1_ENTITY_RPF) | ||
503 | vsp1_rwpf_set_memory(to_rwpf(&entity->subdev), | ||
504 | pipe->dl); | ||
505 | } | 503 | } |
506 | 504 | ||
507 | vsp1_dl_list_commit(pipe->dl); | 505 | vsp1_dl_list_commit(pipe->dl); |
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index cc316d281687..57c713a4e1df 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c | |||
@@ -60,7 +60,7 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data) | |||
60 | status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i)); | 60 | status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i)); |
61 | vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask); | 61 | vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask); |
62 | 62 | ||
63 | if (status & VI6_WFP_IRQ_STA_FRE) { | 63 | if (status & VI6_WFP_IRQ_STA_DFE) { |
64 | vsp1_pipeline_frame_end(wpf->pipe); | 64 | vsp1_pipeline_frame_end(wpf->pipe); |
65 | ret = IRQ_HANDLED; | 65 | ret = IRQ_HANDLED; |
66 | } | 66 | } |
@@ -220,7 +220,8 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) | |||
220 | int ret; | 220 | int ret; |
221 | 221 | ||
222 | mdev->dev = vsp1->dev; | 222 | mdev->dev = vsp1->dev; |
223 | strlcpy(mdev->model, "VSP1", sizeof(mdev->model)); | 223 | mdev->hw_revision = vsp1->version; |
224 | strlcpy(mdev->model, vsp1->info->model, sizeof(mdev->model)); | ||
224 | snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", | 225 | snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", |
225 | dev_name(mdev->dev)); | 226 | dev_name(mdev->dev)); |
226 | media_device_init(mdev); | 227 | media_device_init(mdev); |
@@ -559,6 +560,7 @@ static const struct dev_pm_ops vsp1_pm_ops = { | |||
559 | static const struct vsp1_device_info vsp1_device_infos[] = { | 560 | static const struct vsp1_device_info vsp1_device_infos[] = { |
560 | { | 561 | { |
561 | .version = VI6_IP_VERSION_MODEL_VSPS_H2, | 562 | .version = VI6_IP_VERSION_MODEL_VSPS_H2, |
563 | .model = "VSP1-S", | ||
562 | .gen = 2, | 564 | .gen = 2, |
563 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT | 565 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT |
564 | | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, | 566 | | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, |
@@ -569,6 +571,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
569 | .uapi = true, | 571 | .uapi = true, |
570 | }, { | 572 | }, { |
571 | .version = VI6_IP_VERSION_MODEL_VSPR_H2, | 573 | .version = VI6_IP_VERSION_MODEL_VSPR_H2, |
574 | .model = "VSP1-R", | ||
572 | .gen = 2, | 575 | .gen = 2, |
573 | .features = VSP1_HAS_BRU | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, | 576 | .features = VSP1_HAS_BRU | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, |
574 | .rpf_count = 5, | 577 | .rpf_count = 5, |
@@ -578,6 +581,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
578 | .uapi = true, | 581 | .uapi = true, |
579 | }, { | 582 | }, { |
580 | .version = VI6_IP_VERSION_MODEL_VSPD_GEN2, | 583 | .version = VI6_IP_VERSION_MODEL_VSPD_GEN2, |
584 | .model = "VSP1-D", | ||
581 | .gen = 2, | 585 | .gen = 2, |
582 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT, | 586 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT, |
583 | .rpf_count = 4, | 587 | .rpf_count = 4, |
@@ -587,6 +591,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
587 | .uapi = true, | 591 | .uapi = true, |
588 | }, { | 592 | }, { |
589 | .version = VI6_IP_VERSION_MODEL_VSPS_M2, | 593 | .version = VI6_IP_VERSION_MODEL_VSPS_M2, |
594 | .model = "VSP1-S", | ||
590 | .gen = 2, | 595 | .gen = 2, |
591 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT | 596 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT |
592 | | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, | 597 | | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, |
@@ -596,7 +601,30 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
596 | .num_bru_inputs = 4, | 601 | .num_bru_inputs = 4, |
597 | .uapi = true, | 602 | .uapi = true, |
598 | }, { | 603 | }, { |
604 | .version = VI6_IP_VERSION_MODEL_VSPS_V2H, | ||
605 | .model = "VSP1V-S", | ||
606 | .gen = 2, | ||
607 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT | ||
608 | | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, | ||
609 | .rpf_count = 4, | ||
610 | .uds_count = 1, | ||
611 | .wpf_count = 4, | ||
612 | .num_bru_inputs = 4, | ||
613 | .uapi = true, | ||
614 | }, { | ||
615 | .version = VI6_IP_VERSION_MODEL_VSPD_V2H, | ||
616 | .model = "VSP1V-D", | ||
617 | .gen = 2, | ||
618 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT | ||
619 | | VSP1_HAS_LIF, | ||
620 | .rpf_count = 4, | ||
621 | .uds_count = 1, | ||
622 | .wpf_count = 1, | ||
623 | .num_bru_inputs = 4, | ||
624 | .uapi = true, | ||
625 | }, { | ||
599 | .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, | 626 | .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, |
627 | .model = "VSP2-I", | ||
600 | .gen = 3, | 628 | .gen = 3, |
601 | .features = VSP1_HAS_CLU | VSP1_HAS_LUT | VSP1_HAS_SRU | 629 | .features = VSP1_HAS_CLU | VSP1_HAS_LUT | VSP1_HAS_SRU |
602 | | VSP1_HAS_WPF_HFLIP | VSP1_HAS_WPF_VFLIP, | 630 | | VSP1_HAS_WPF_HFLIP | VSP1_HAS_WPF_VFLIP, |
@@ -606,6 +634,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
606 | .uapi = true, | 634 | .uapi = true, |
607 | }, { | 635 | }, { |
608 | .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3, | 636 | .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3, |
637 | .model = "VSP2-BD", | ||
609 | .gen = 3, | 638 | .gen = 3, |
610 | .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP, | 639 | .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP, |
611 | .rpf_count = 5, | 640 | .rpf_count = 5, |
@@ -614,6 +643,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
614 | .uapi = true, | 643 | .uapi = true, |
615 | }, { | 644 | }, { |
616 | .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, | 645 | .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, |
646 | .model = "VSP2-BC", | ||
617 | .gen = 3, | 647 | .gen = 3, |
618 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT | 648 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT |
619 | | VSP1_HAS_WPF_VFLIP, | 649 | | VSP1_HAS_WPF_VFLIP, |
@@ -623,6 +653,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
623 | .uapi = true, | 653 | .uapi = true, |
624 | }, { | 654 | }, { |
625 | .version = VI6_IP_VERSION_MODEL_VSPD_GEN3, | 655 | .version = VI6_IP_VERSION_MODEL_VSPD_GEN3, |
656 | .model = "VSP2-D", | ||
626 | .gen = 3, | 657 | .gen = 3, |
627 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_WPF_VFLIP, | 658 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_WPF_VFLIP, |
628 | .rpf_count = 5, | 659 | .rpf_count = 5, |
@@ -638,7 +669,6 @@ static int vsp1_probe(struct platform_device *pdev) | |||
638 | struct resource *irq; | 669 | struct resource *irq; |
639 | struct resource *io; | 670 | struct resource *io; |
640 | unsigned int i; | 671 | unsigned int i; |
641 | u32 version; | ||
642 | int ret; | 672 | int ret; |
643 | 673 | ||
644 | vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL); | 674 | vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL); |
@@ -689,11 +719,11 @@ static int vsp1_probe(struct platform_device *pdev) | |||
689 | if (ret < 0) | 719 | if (ret < 0) |
690 | goto done; | 720 | goto done; |
691 | 721 | ||
692 | version = vsp1_read(vsp1, VI6_IP_VERSION); | 722 | vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION); |
693 | pm_runtime_put_sync(&pdev->dev); | 723 | pm_runtime_put_sync(&pdev->dev); |
694 | 724 | ||
695 | for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { | 725 | for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { |
696 | if ((version & VI6_IP_VERSION_MODEL_MASK) == | 726 | if ((vsp1->version & VI6_IP_VERSION_MODEL_MASK) == |
697 | vsp1_device_infos[i].version) { | 727 | vsp1_device_infos[i].version) { |
698 | vsp1->info = &vsp1_device_infos[i]; | 728 | vsp1->info = &vsp1_device_infos[i]; |
699 | break; | 729 | break; |
@@ -701,12 +731,13 @@ static int vsp1_probe(struct platform_device *pdev) | |||
701 | } | 731 | } |
702 | 732 | ||
703 | if (!vsp1->info) { | 733 | if (!vsp1->info) { |
704 | dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", version); | 734 | dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", |
735 | vsp1->version); | ||
705 | ret = -ENXIO; | 736 | ret = -ENXIO; |
706 | goto done; | 737 | goto done; |
707 | } | 738 | } |
708 | 739 | ||
709 | dev_dbg(&pdev->dev, "IP version 0x%08x\n", version); | 740 | dev_dbg(&pdev->dev, "IP version 0x%08x\n", vsp1->version); |
710 | 741 | ||
711 | /* Instanciate entities */ | 742 | /* Instanciate entities */ |
712 | ret = vsp1_create_entities(vsp1); | 743 | ret = vsp1_create_entities(vsp1); |
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 4cf6cc719c00..da673495c222 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c | |||
@@ -51,6 +51,9 @@ void vsp1_entity_route_setup(struct vsp1_entity *source, | |||
51 | * @cfg: the TRY pad configuration | 51 | * @cfg: the TRY pad configuration |
52 | * @which: configuration selector (ACTIVE or TRY) | 52 | * @which: configuration selector (ACTIVE or TRY) |
53 | * | 53 | * |
54 | * When called with which set to V4L2_SUBDEV_FORMAT_ACTIVE the caller must hold | ||
55 | * the entity lock to access the returned configuration. | ||
56 | * | ||
54 | * Return the pad configuration requested by the which argument. The TRY | 57 | * Return the pad configuration requested by the which argument. The TRY |
55 | * configuration is passed explicitly to the function through the cfg argument | 58 | * configuration is passed explicitly to the function through the cfg argument |
56 | * and simply returned when requested. The ACTIVE configuration comes from the | 59 | * and simply returned when requested. The ACTIVE configuration comes from the |
@@ -160,7 +163,9 @@ int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev, | |||
160 | if (!config) | 163 | if (!config) |
161 | return -EINVAL; | 164 | return -EINVAL; |
162 | 165 | ||
166 | mutex_lock(&entity->lock); | ||
163 | fmt->format = *vsp1_entity_get_pad_format(entity, config, fmt->pad); | 167 | fmt->format = *vsp1_entity_get_pad_format(entity, config, fmt->pad); |
168 | mutex_unlock(&entity->lock); | ||
164 | 169 | ||
165 | return 0; | 170 | return 0; |
166 | } | 171 | } |
@@ -204,8 +209,10 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev, | |||
204 | if (!config) | 209 | if (!config) |
205 | return -EINVAL; | 210 | return -EINVAL; |
206 | 211 | ||
212 | mutex_lock(&entity->lock); | ||
207 | format = vsp1_entity_get_pad_format(entity, config, 0); | 213 | format = vsp1_entity_get_pad_format(entity, config, 0); |
208 | code->code = format->code; | 214 | code->code = format->code; |
215 | mutex_unlock(&entity->lock); | ||
209 | } | 216 | } |
210 | 217 | ||
211 | return 0; | 218 | return 0; |
@@ -235,6 +242,7 @@ int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev, | |||
235 | struct vsp1_entity *entity = to_vsp1_entity(subdev); | 242 | struct vsp1_entity *entity = to_vsp1_entity(subdev); |
236 | struct v4l2_subdev_pad_config *config; | 243 | struct v4l2_subdev_pad_config *config; |
237 | struct v4l2_mbus_framefmt *format; | 244 | struct v4l2_mbus_framefmt *format; |
245 | int ret = 0; | ||
238 | 246 | ||
239 | config = vsp1_entity_get_pad_config(entity, cfg, fse->which); | 247 | config = vsp1_entity_get_pad_config(entity, cfg, fse->which); |
240 | if (!config) | 248 | if (!config) |
@@ -242,8 +250,12 @@ int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev, | |||
242 | 250 | ||
243 | format = vsp1_entity_get_pad_format(entity, config, fse->pad); | 251 | format = vsp1_entity_get_pad_format(entity, config, fse->pad); |
244 | 252 | ||
245 | if (fse->index || fse->code != format->code) | 253 | mutex_lock(&entity->lock); |
246 | return -EINVAL; | 254 | |
255 | if (fse->index || fse->code != format->code) { | ||
256 | ret = -EINVAL; | ||
257 | goto done; | ||
258 | } | ||
247 | 259 | ||
248 | if (fse->pad == 0) { | 260 | if (fse->pad == 0) { |
249 | fse->min_width = min_width; | 261 | fse->min_width = min_width; |
@@ -260,7 +272,9 @@ int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev, | |||
260 | fse->max_height = format->height; | 272 | fse->max_height = format->height; |
261 | } | 273 | } |
262 | 274 | ||
263 | return 0; | 275 | done: |
276 | mutex_unlock(&entity->lock); | ||
277 | return ret; | ||
264 | } | 278 | } |
265 | 279 | ||
266 | /* ----------------------------------------------------------------------------- | 280 | /* ----------------------------------------------------------------------------- |
@@ -358,6 +372,8 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, | |||
358 | if (i == ARRAY_SIZE(vsp1_routes)) | 372 | if (i == ARRAY_SIZE(vsp1_routes)) |
359 | return -EINVAL; | 373 | return -EINVAL; |
360 | 374 | ||
375 | mutex_init(&entity->lock); | ||
376 | |||
361 | entity->vsp1 = vsp1; | 377 | entity->vsp1 = vsp1; |
362 | entity->source_pad = num_pads - 1; | 378 | entity->source_pad = num_pads - 1; |
363 | 379 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index b43457fd2c43..901146f807b9 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h | |||
@@ -14,7 +14,7 @@ | |||
14 | #define __VSP1_ENTITY_H__ | 14 | #define __VSP1_ENTITY_H__ |
15 | 15 | ||
16 | #include <linux/list.h> | 16 | #include <linux/list.h> |
17 | #include <linux/spinlock.h> | 17 | #include <linux/mutex.h> |
18 | 18 | ||
19 | #include <media/v4l2-subdev.h> | 19 | #include <media/v4l2-subdev.h> |
20 | 20 | ||
@@ -35,6 +35,18 @@ enum vsp1_entity_type { | |||
35 | VSP1_ENTITY_WPF, | 35 | VSP1_ENTITY_WPF, |
36 | }; | 36 | }; |
37 | 37 | ||
38 | /** | ||
39 | * enum vsp1_entity_params - Entity configuration parameters class | ||
40 | * @VSP1_ENTITY_PARAMS_INIT - Initial parameters | ||
41 | * @VSP1_ENTITY_PARAMS_PARTITION - Per-image partition parameters | ||
42 | * @VSP1_ENTITY_PARAMS_RUNTIME - Runtime-configurable parameters | ||
43 | */ | ||
44 | enum vsp1_entity_params { | ||
45 | VSP1_ENTITY_PARAMS_INIT, | ||
46 | VSP1_ENTITY_PARAMS_PARTITION, | ||
47 | VSP1_ENTITY_PARAMS_RUNTIME, | ||
48 | }; | ||
49 | |||
38 | #define VSP1_ENTITY_MAX_INPUTS 5 /* For the BRU */ | 50 | #define VSP1_ENTITY_MAX_INPUTS 5 /* For the BRU */ |
39 | 51 | ||
40 | /* | 52 | /* |
@@ -63,17 +75,16 @@ struct vsp1_route { | |||
63 | /** | 75 | /** |
64 | * struct vsp1_entity_operations - Entity operations | 76 | * struct vsp1_entity_operations - Entity operations |
65 | * @destroy: Destroy the entity. | 77 | * @destroy: Destroy the entity. |
66 | * @set_memory: Setup memory buffer access. This operation applies the settings | ||
67 | * stored in the rwpf mem field to the display list. Valid for RPF | ||
68 | * and WPF only. | ||
69 | * @configure: Setup the hardware based on the entity state (pipeline, formats, | 78 | * @configure: Setup the hardware based on the entity state (pipeline, formats, |
70 | * selection rectangles, ...) | 79 | * selection rectangles, ...) |
80 | * @max_width: Return the max supported width of data that the entity can | ||
81 | * process in a single operation. | ||
71 | */ | 82 | */ |
72 | struct vsp1_entity_operations { | 83 | struct vsp1_entity_operations { |
73 | void (*destroy)(struct vsp1_entity *); | 84 | void (*destroy)(struct vsp1_entity *); |
74 | void (*set_memory)(struct vsp1_entity *, struct vsp1_dl_list *dl); | ||
75 | void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *, | 85 | void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *, |
76 | struct vsp1_dl_list *, bool); | 86 | struct vsp1_dl_list *, enum vsp1_entity_params); |
87 | unsigned int (*max_width)(struct vsp1_entity *, struct vsp1_pipeline *); | ||
77 | }; | 88 | }; |
78 | 89 | ||
79 | struct vsp1_entity { | 90 | struct vsp1_entity { |
@@ -96,6 +107,8 @@ struct vsp1_entity { | |||
96 | 107 | ||
97 | struct v4l2_subdev subdev; | 108 | struct v4l2_subdev subdev; |
98 | struct v4l2_subdev_pad_config *config; | 109 | struct v4l2_subdev_pad_config *config; |
110 | |||
111 | struct mutex lock; /* Protects the pad config */ | ||
99 | }; | 112 | }; |
100 | 113 | ||
101 | static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev) | 114 | static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev) |
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index 6e5077beb38c..94316afc54ff 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c | |||
@@ -71,10 +71,15 @@ static int hsit_set_format(struct v4l2_subdev *subdev, | |||
71 | struct vsp1_hsit *hsit = to_hsit(subdev); | 71 | struct vsp1_hsit *hsit = to_hsit(subdev); |
72 | struct v4l2_subdev_pad_config *config; | 72 | struct v4l2_subdev_pad_config *config; |
73 | struct v4l2_mbus_framefmt *format; | 73 | struct v4l2_mbus_framefmt *format; |
74 | int ret = 0; | ||
75 | |||
76 | mutex_lock(&hsit->entity.lock); | ||
74 | 77 | ||
75 | config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fmt->which); | 78 | config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fmt->which); |
76 | if (!config) | 79 | if (!config) { |
77 | return -EINVAL; | 80 | ret = -EINVAL; |
81 | goto done; | ||
82 | } | ||
78 | 83 | ||
79 | format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad); | 84 | format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad); |
80 | 85 | ||
@@ -83,7 +88,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev, | |||
83 | * modified. | 88 | * modified. |
84 | */ | 89 | */ |
85 | fmt->format = *format; | 90 | fmt->format = *format; |
86 | return 0; | 91 | goto done; |
87 | } | 92 | } |
88 | 93 | ||
89 | format->code = hsit->inverse ? MEDIA_BUS_FMT_AHSV8888_1X32 | 94 | format->code = hsit->inverse ? MEDIA_BUS_FMT_AHSV8888_1X32 |
@@ -104,7 +109,9 @@ static int hsit_set_format(struct v4l2_subdev *subdev, | |||
104 | format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32 | 109 | format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32 |
105 | : MEDIA_BUS_FMT_AHSV8888_1X32; | 110 | : MEDIA_BUS_FMT_AHSV8888_1X32; |
106 | 111 | ||
107 | return 0; | 112 | done: |
113 | mutex_unlock(&hsit->entity.lock); | ||
114 | return ret; | ||
108 | } | 115 | } |
109 | 116 | ||
110 | static const struct v4l2_subdev_pad_ops hsit_pad_ops = { | 117 | static const struct v4l2_subdev_pad_ops hsit_pad_ops = { |
@@ -125,11 +132,12 @@ static const struct v4l2_subdev_ops hsit_ops = { | |||
125 | 132 | ||
126 | static void hsit_configure(struct vsp1_entity *entity, | 133 | static void hsit_configure(struct vsp1_entity *entity, |
127 | struct vsp1_pipeline *pipe, | 134 | struct vsp1_pipeline *pipe, |
128 | struct vsp1_dl_list *dl, bool full) | 135 | struct vsp1_dl_list *dl, |
136 | enum vsp1_entity_params params) | ||
129 | { | 137 | { |
130 | struct vsp1_hsit *hsit = to_hsit(&entity->subdev); | 138 | struct vsp1_hsit *hsit = to_hsit(&entity->subdev); |
131 | 139 | ||
132 | if (!full) | 140 | if (params != VSP1_ENTITY_PARAMS_INIT) |
133 | return; | 141 | return; |
134 | 142 | ||
135 | if (hsit->inverse) | 143 | if (hsit->inverse) |
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index a720063f38c5..e32acae1fc6e 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c | |||
@@ -66,10 +66,15 @@ static int lif_set_format(struct v4l2_subdev *subdev, | |||
66 | struct vsp1_lif *lif = to_lif(subdev); | 66 | struct vsp1_lif *lif = to_lif(subdev); |
67 | struct v4l2_subdev_pad_config *config; | 67 | struct v4l2_subdev_pad_config *config; |
68 | struct v4l2_mbus_framefmt *format; | 68 | struct v4l2_mbus_framefmt *format; |
69 | int ret = 0; | ||
70 | |||
71 | mutex_lock(&lif->entity.lock); | ||
69 | 72 | ||
70 | config = vsp1_entity_get_pad_config(&lif->entity, cfg, fmt->which); | 73 | config = vsp1_entity_get_pad_config(&lif->entity, cfg, fmt->which); |
71 | if (!config) | 74 | if (!config) { |
72 | return -EINVAL; | 75 | ret = -EINVAL; |
76 | goto done; | ||
77 | } | ||
73 | 78 | ||
74 | /* Default to YUV if the requested format is not supported. */ | 79 | /* Default to YUV if the requested format is not supported. */ |
75 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && | 80 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && |
@@ -83,7 +88,7 @@ static int lif_set_format(struct v4l2_subdev *subdev, | |||
83 | * format. | 88 | * format. |
84 | */ | 89 | */ |
85 | fmt->format = *format; | 90 | fmt->format = *format; |
86 | return 0; | 91 | goto done; |
87 | } | 92 | } |
88 | 93 | ||
89 | format->code = fmt->format.code; | 94 | format->code = fmt->format.code; |
@@ -101,7 +106,9 @@ static int lif_set_format(struct v4l2_subdev *subdev, | |||
101 | LIF_PAD_SOURCE); | 106 | LIF_PAD_SOURCE); |
102 | *format = fmt->format; | 107 | *format = fmt->format; |
103 | 108 | ||
104 | return 0; | 109 | done: |
110 | mutex_unlock(&lif->entity.lock); | ||
111 | return ret; | ||
105 | } | 112 | } |
106 | 113 | ||
107 | static const struct v4l2_subdev_pad_ops lif_pad_ops = { | 114 | static const struct v4l2_subdev_pad_ops lif_pad_ops = { |
@@ -122,7 +129,8 @@ static const struct v4l2_subdev_ops lif_ops = { | |||
122 | 129 | ||
123 | static void lif_configure(struct vsp1_entity *entity, | 130 | static void lif_configure(struct vsp1_entity *entity, |
124 | struct vsp1_pipeline *pipe, | 131 | struct vsp1_pipeline *pipe, |
125 | struct vsp1_dl_list *dl, bool full) | 132 | struct vsp1_dl_list *dl, |
133 | enum vsp1_entity_params params) | ||
126 | { | 134 | { |
127 | const struct v4l2_mbus_framefmt *format; | 135 | const struct v4l2_mbus_framefmt *format; |
128 | struct vsp1_lif *lif = to_lif(&entity->subdev); | 136 | struct vsp1_lif *lif = to_lif(&entity->subdev); |
@@ -130,7 +138,7 @@ static void lif_configure(struct vsp1_entity *entity, | |||
130 | unsigned int obth = 400; | 138 | unsigned int obth = 400; |
131 | unsigned int lbth = 200; | 139 | unsigned int lbth = 200; |
132 | 140 | ||
133 | if (!full) | 141 | if (params != VSP1_ENTITY_PARAMS_INIT) |
134 | return; | 142 | return; |
135 | 143 | ||
136 | format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config, | 144 | format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config, |
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index dc31de9602ba..c67cc60db0db 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c | |||
@@ -124,10 +124,15 @@ static int lut_set_format(struct v4l2_subdev *subdev, | |||
124 | struct vsp1_lut *lut = to_lut(subdev); | 124 | struct vsp1_lut *lut = to_lut(subdev); |
125 | struct v4l2_subdev_pad_config *config; | 125 | struct v4l2_subdev_pad_config *config; |
126 | struct v4l2_mbus_framefmt *format; | 126 | struct v4l2_mbus_framefmt *format; |
127 | int ret = 0; | ||
128 | |||
129 | mutex_lock(&lut->entity.lock); | ||
127 | 130 | ||
128 | config = vsp1_entity_get_pad_config(&lut->entity, cfg, fmt->which); | 131 | config = vsp1_entity_get_pad_config(&lut->entity, cfg, fmt->which); |
129 | if (!config) | 132 | if (!config) { |
130 | return -EINVAL; | 133 | ret = -EINVAL; |
134 | goto done; | ||
135 | } | ||
131 | 136 | ||
132 | /* Default to YUV if the requested format is not supported. */ | 137 | /* Default to YUV if the requested format is not supported. */ |
133 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && | 138 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && |
@@ -140,7 +145,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, | |||
140 | if (fmt->pad == LUT_PAD_SOURCE) { | 145 | if (fmt->pad == LUT_PAD_SOURCE) { |
141 | /* The LUT output format can't be modified. */ | 146 | /* The LUT output format can't be modified. */ |
142 | fmt->format = *format; | 147 | fmt->format = *format; |
143 | return 0; | 148 | goto done; |
144 | } | 149 | } |
145 | 150 | ||
146 | format->code = fmt->format.code; | 151 | format->code = fmt->format.code; |
@@ -158,7 +163,9 @@ static int lut_set_format(struct v4l2_subdev *subdev, | |||
158 | LUT_PAD_SOURCE); | 163 | LUT_PAD_SOURCE); |
159 | *format = fmt->format; | 164 | *format = fmt->format; |
160 | 165 | ||
161 | return 0; | 166 | done: |
167 | mutex_unlock(&lut->entity.lock); | ||
168 | return ret; | ||
162 | } | 169 | } |
163 | 170 | ||
164 | /* ----------------------------------------------------------------------------- | 171 | /* ----------------------------------------------------------------------------- |
@@ -183,24 +190,31 @@ static const struct v4l2_subdev_ops lut_ops = { | |||
183 | 190 | ||
184 | static void lut_configure(struct vsp1_entity *entity, | 191 | static void lut_configure(struct vsp1_entity *entity, |
185 | struct vsp1_pipeline *pipe, | 192 | struct vsp1_pipeline *pipe, |
186 | struct vsp1_dl_list *dl, bool full) | 193 | struct vsp1_dl_list *dl, |
194 | enum vsp1_entity_params params) | ||
187 | { | 195 | { |
188 | struct vsp1_lut *lut = to_lut(&entity->subdev); | 196 | struct vsp1_lut *lut = to_lut(&entity->subdev); |
189 | struct vsp1_dl_body *dlb; | 197 | struct vsp1_dl_body *dlb; |
190 | unsigned long flags; | 198 | unsigned long flags; |
191 | 199 | ||
192 | if (full) { | 200 | switch (params) { |
201 | case VSP1_ENTITY_PARAMS_INIT: | ||
193 | vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); | 202 | vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); |
194 | return; | 203 | break; |
195 | } | ||
196 | 204 | ||
197 | spin_lock_irqsave(&lut->lock, flags); | 205 | case VSP1_ENTITY_PARAMS_PARTITION: |
198 | dlb = lut->lut; | 206 | break; |
199 | lut->lut = NULL; | 207 | |
200 | spin_unlock_irqrestore(&lut->lock, flags); | 208 | case VSP1_ENTITY_PARAMS_RUNTIME: |
209 | spin_lock_irqsave(&lut->lock, flags); | ||
210 | dlb = lut->lut; | ||
211 | lut->lut = NULL; | ||
212 | spin_unlock_irqrestore(&lut->lock, flags); | ||
201 | 213 | ||
202 | if (dlb) | 214 | if (dlb) |
203 | vsp1_dl_list_add_fragment(dl, dlb); | 215 | vsp1_dl_list_add_fragment(dl, dlb); |
216 | break; | ||
217 | } | ||
204 | } | 218 | } |
205 | 219 | ||
206 | static const struct vsp1_entity_operations lut_entity_ops = { | 220 | static const struct vsp1_entity_operations lut_entity_ops = { |
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index 3e75fb3fcace..756ca4ea7668 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c | |||
@@ -136,17 +136,23 @@ static const struct vsp1_format_info vsp1_video_formats[] = { | |||
136 | 3, { 8, 8, 8 }, false, true, 1, 1, false }, | 136 | 3, { 8, 8, 8 }, false, true, 1, 1, false }, |
137 | }; | 137 | }; |
138 | 138 | ||
139 | /* | 139 | /** |
140 | * vsp1_get_format_info - Retrieve format information for a 4CC | 140 | * vsp1_get_format_info - Retrieve format information for a 4CC |
141 | * @vsp1: the VSP1 device | ||
141 | * @fourcc: the format 4CC | 142 | * @fourcc: the format 4CC |
142 | * | 143 | * |
143 | * Return a pointer to the format information structure corresponding to the | 144 | * Return a pointer to the format information structure corresponding to the |
144 | * given V4L2 format 4CC, or NULL if no corresponding format can be found. | 145 | * given V4L2 format 4CC, or NULL if no corresponding format can be found. |
145 | */ | 146 | */ |
146 | const struct vsp1_format_info *vsp1_get_format_info(u32 fourcc) | 147 | const struct vsp1_format_info *vsp1_get_format_info(struct vsp1_device *vsp1, |
148 | u32 fourcc) | ||
147 | { | 149 | { |
148 | unsigned int i; | 150 | unsigned int i; |
149 | 151 | ||
152 | /* Special case, the VYUY format is supported on Gen2 only. */ | ||
153 | if (vsp1->info->gen != 2 && fourcc == V4L2_PIX_FMT_VYUY) | ||
154 | return NULL; | ||
155 | |||
150 | for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) { | 156 | for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) { |
151 | const struct vsp1_format_info *info = &vsp1_video_formats[i]; | 157 | const struct vsp1_format_info *info = &vsp1_video_formats[i]; |
152 | 158 | ||
@@ -365,6 +371,7 @@ void vsp1_pipelines_suspend(struct vsp1_device *vsp1) | |||
365 | 371 | ||
366 | void vsp1_pipelines_resume(struct vsp1_device *vsp1) | 372 | void vsp1_pipelines_resume(struct vsp1_device *vsp1) |
367 | { | 373 | { |
374 | unsigned long flags; | ||
368 | unsigned int i; | 375 | unsigned int i; |
369 | 376 | ||
370 | /* Resume all running pipelines. */ | 377 | /* Resume all running pipelines. */ |
@@ -379,7 +386,9 @@ void vsp1_pipelines_resume(struct vsp1_device *vsp1) | |||
379 | if (pipe == NULL) | 386 | if (pipe == NULL) |
380 | continue; | 387 | continue; |
381 | 388 | ||
389 | spin_lock_irqsave(&pipe->irqlock, flags); | ||
382 | if (vsp1_pipeline_ready(pipe)) | 390 | if (vsp1_pipeline_ready(pipe)) |
383 | vsp1_pipeline_run(pipe); | 391 | vsp1_pipeline_run(pipe); |
392 | spin_unlock_irqrestore(&pipe->irqlock, flags); | ||
384 | } | 393 | } |
385 | } | 394 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h index d20d997b1fda..ac4ad2655551 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.h +++ b/drivers/media/platform/vsp1/vsp1_pipe.h | |||
@@ -77,6 +77,9 @@ enum vsp1_pipeline_state { | |||
77 | * @uds_input: entity at the input of the UDS, if the UDS is present | 77 | * @uds_input: entity at the input of the UDS, if the UDS is present |
78 | * @entities: list of entities in the pipeline | 78 | * @entities: list of entities in the pipeline |
79 | * @dl: display list associated with the pipeline | 79 | * @dl: display list associated with the pipeline |
80 | * @div_size: The maximum allowed partition size for the pipeline | ||
81 | * @partitions: The number of partitions used to process one frame | ||
82 | * @current_partition: The partition number currently being configured | ||
80 | */ | 83 | */ |
81 | struct vsp1_pipeline { | 84 | struct vsp1_pipeline { |
82 | struct media_pipeline pipe; | 85 | struct media_pipeline pipe; |
@@ -104,6 +107,11 @@ struct vsp1_pipeline { | |||
104 | struct list_head entities; | 107 | struct list_head entities; |
105 | 108 | ||
106 | struct vsp1_dl_list *dl; | 109 | struct vsp1_dl_list *dl; |
110 | |||
111 | unsigned int div_size; | ||
112 | unsigned int partitions; | ||
113 | struct v4l2_rect partition; | ||
114 | unsigned int current_partition; | ||
107 | }; | 115 | }; |
108 | 116 | ||
109 | void vsp1_pipeline_reset(struct vsp1_pipeline *pipe); | 117 | void vsp1_pipeline_reset(struct vsp1_pipeline *pipe); |
@@ -122,6 +130,7 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, | |||
122 | void vsp1_pipelines_suspend(struct vsp1_device *vsp1); | 130 | void vsp1_pipelines_suspend(struct vsp1_device *vsp1); |
123 | void vsp1_pipelines_resume(struct vsp1_device *vsp1); | 131 | void vsp1_pipelines_resume(struct vsp1_device *vsp1); |
124 | 132 | ||
125 | const struct vsp1_format_info *vsp1_get_format_info(u32 fourcc); | 133 | const struct vsp1_format_info *vsp1_get_format_info(struct vsp1_device *vsp1, |
134 | u32 fourcc); | ||
126 | 135 | ||
127 | #endif /* __VSP1_PIPE_H__ */ | 136 | #endif /* __VSP1_PIPE_H__ */ |
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 3b03007ba625..47b1dee044fb 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h | |||
@@ -660,6 +660,8 @@ | |||
660 | #define VI6_IP_VERSION_MODEL_VSPR_H2 (0x0a << 8) | 660 | #define VI6_IP_VERSION_MODEL_VSPR_H2 (0x0a << 8) |
661 | #define VI6_IP_VERSION_MODEL_VSPD_GEN2 (0x0b << 8) | 661 | #define VI6_IP_VERSION_MODEL_VSPD_GEN2 (0x0b << 8) |
662 | #define VI6_IP_VERSION_MODEL_VSPS_M2 (0x0c << 8) | 662 | #define VI6_IP_VERSION_MODEL_VSPS_M2 (0x0c << 8) |
663 | #define VI6_IP_VERSION_MODEL_VSPS_V2H (0x12 << 8) | ||
664 | #define VI6_IP_VERSION_MODEL_VSPD_V2H (0x13 << 8) | ||
663 | #define VI6_IP_VERSION_MODEL_VSPI_GEN3 (0x14 << 8) | 665 | #define VI6_IP_VERSION_MODEL_VSPI_GEN3 (0x14 << 8) |
664 | #define VI6_IP_VERSION_MODEL_VSPBD_GEN3 (0x15 << 8) | 666 | #define VI6_IP_VERSION_MODEL_VSPBD_GEN3 (0x15 << 8) |
665 | #define VI6_IP_VERSION_MODEL_VSPBC_GEN3 (0x16 << 8) | 667 | #define VI6_IP_VERSION_MODEL_VSPBC_GEN3 (0x16 << 8) |
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 388838913205..b2e34a800ffa 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c | |||
@@ -46,34 +46,22 @@ static const struct v4l2_subdev_ops rpf_ops = { | |||
46 | * VSP1 Entity Operations | 46 | * VSP1 Entity Operations |
47 | */ | 47 | */ |
48 | 48 | ||
49 | static void rpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) | ||
50 | { | ||
51 | struct vsp1_rwpf *rpf = entity_to_rwpf(entity); | ||
52 | |||
53 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y, | ||
54 | rpf->mem.addr[0] + rpf->offsets[0]); | ||
55 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0, | ||
56 | rpf->mem.addr[1] + rpf->offsets[1]); | ||
57 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1, | ||
58 | rpf->mem.addr[2] + rpf->offsets[1]); | ||
59 | } | ||
60 | |||
61 | static void rpf_configure(struct vsp1_entity *entity, | 49 | static void rpf_configure(struct vsp1_entity *entity, |
62 | struct vsp1_pipeline *pipe, | 50 | struct vsp1_pipeline *pipe, |
63 | struct vsp1_dl_list *dl, bool full) | 51 | struct vsp1_dl_list *dl, |
52 | enum vsp1_entity_params params) | ||
64 | { | 53 | { |
65 | struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); | 54 | struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); |
66 | const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; | 55 | const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; |
67 | const struct v4l2_pix_format_mplane *format = &rpf->format; | 56 | const struct v4l2_pix_format_mplane *format = &rpf->format; |
68 | const struct v4l2_mbus_framefmt *source_format; | 57 | const struct v4l2_mbus_framefmt *source_format; |
69 | const struct v4l2_mbus_framefmt *sink_format; | 58 | const struct v4l2_mbus_framefmt *sink_format; |
70 | const struct v4l2_rect *crop; | ||
71 | unsigned int left = 0; | 59 | unsigned int left = 0; |
72 | unsigned int top = 0; | 60 | unsigned int top = 0; |
73 | u32 pstride; | 61 | u32 pstride; |
74 | u32 infmt; | 62 | u32 infmt; |
75 | 63 | ||
76 | if (!full) { | 64 | if (params == VSP1_ENTITY_PARAMS_RUNTIME) { |
77 | vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET, | 65 | vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET, |
78 | rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); | 66 | rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); |
79 | vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, rpf->mult_alpha | | 67 | vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, rpf->mult_alpha | |
@@ -83,34 +71,80 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
83 | return; | 71 | return; |
84 | } | 72 | } |
85 | 73 | ||
86 | /* Source size, stride and crop offsets. | 74 | if (params == VSP1_ENTITY_PARAMS_PARTITION) { |
87 | * | 75 | unsigned int offsets[2]; |
88 | * The crop offsets correspond to the location of the crop rectangle top | 76 | struct v4l2_rect crop; |
89 | * left corner in the plane buffer. Only two offsets are needed, as | 77 | |
90 | * planes 2 and 3 always have identical strides. | 78 | /* |
91 | */ | 79 | * Source size and crop offsets. |
92 | crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config); | 80 | * |
81 | * The crop offsets correspond to the location of the crop | ||
82 | * rectangle top left corner in the plane buffer. Only two | ||
83 | * offsets are needed, as planes 2 and 3 always have identical | ||
84 | * strides. | ||
85 | */ | ||
86 | crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.config); | ||
87 | |||
88 | /* | ||
89 | * Partition Algorithm Control | ||
90 | * | ||
91 | * The partition algorithm can split this frame into multiple | ||
92 | * slices. We must scale our partition window based on the pipe | ||
93 | * configuration to match the destination partition window. | ||
94 | * To achieve this, we adjust our crop to provide a 'sub-crop' | ||
95 | * matching the expected partition window. Only 'left' and | ||
96 | * 'width' need to be adjusted. | ||
97 | */ | ||
98 | if (pipe->partitions > 1) { | ||
99 | const struct v4l2_mbus_framefmt *output; | ||
100 | struct vsp1_entity *wpf = &pipe->output->entity; | ||
101 | unsigned int input_width = crop.width; | ||
102 | |||
103 | /* | ||
104 | * Scale the partition window based on the configuration | ||
105 | * of the pipeline. | ||
106 | */ | ||
107 | output = vsp1_entity_get_pad_format(wpf, wpf->config, | ||
108 | RWPF_PAD_SOURCE); | ||
93 | 109 | ||
94 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE, | 110 | crop.width = pipe->partition.width * input_width |
95 | (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) | | 111 | / output->width; |
96 | (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT)); | 112 | crop.left += pipe->partition.left * input_width |
97 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE, | 113 | / output->width; |
98 | (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | | 114 | } |
99 | (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); | 115 | |
116 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE, | ||
117 | (crop.width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) | | ||
118 | (crop.height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT)); | ||
119 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE, | ||
120 | (crop.width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | | ||
121 | (crop.height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); | ||
122 | |||
123 | offsets[0] = crop.top * format->plane_fmt[0].bytesperline | ||
124 | + crop.left * fmtinfo->bpp[0] / 8; | ||
125 | |||
126 | if (format->num_planes > 1) | ||
127 | offsets[1] = crop.top * format->plane_fmt[1].bytesperline | ||
128 | + crop.left / fmtinfo->hsub | ||
129 | * fmtinfo->bpp[1] / 8; | ||
130 | else | ||
131 | offsets[1] = 0; | ||
132 | |||
133 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y, | ||
134 | rpf->mem.addr[0] + offsets[0]); | ||
135 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0, | ||
136 | rpf->mem.addr[1] + offsets[1]); | ||
137 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1, | ||
138 | rpf->mem.addr[2] + offsets[1]); | ||
139 | return; | ||
140 | } | ||
100 | 141 | ||
101 | rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline | 142 | /* Stride */ |
102 | + crop->left * fmtinfo->bpp[0] / 8; | ||
103 | pstride = format->plane_fmt[0].bytesperline | 143 | pstride = format->plane_fmt[0].bytesperline |
104 | << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT; | 144 | << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT; |
105 | 145 | if (format->num_planes > 1) | |
106 | if (format->num_planes > 1) { | ||
107 | rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline | ||
108 | + crop->left * fmtinfo->bpp[1] / 8; | ||
109 | pstride |= format->plane_fmt[1].bytesperline | 146 | pstride |= format->plane_fmt[1].bytesperline |
110 | << VI6_RPF_SRCM_PSTRIDE_C_SHIFT; | 147 | << VI6_RPF_SRCM_PSTRIDE_C_SHIFT; |
111 | } else { | ||
112 | rpf->offsets[1] = 0; | ||
113 | } | ||
114 | 148 | ||
115 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_PSTRIDE, pstride); | 149 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_PSTRIDE, pstride); |
116 | 150 | ||
@@ -215,7 +249,6 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
215 | } | 249 | } |
216 | 250 | ||
217 | static const struct vsp1_entity_operations rpf_entity_ops = { | 251 | static const struct vsp1_entity_operations rpf_entity_ops = { |
218 | .set_memory = rpf_set_memory, | ||
219 | .configure = rpf_configure, | 252 | .configure = rpf_configure, |
220 | }; | 253 | }; |
221 | 254 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index 8d461b375e91..66e4d7ea31d6 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c | |||
@@ -66,11 +66,15 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, | |||
66 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | 66 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); |
67 | struct v4l2_subdev_pad_config *config; | 67 | struct v4l2_subdev_pad_config *config; |
68 | struct v4l2_mbus_framefmt *format; | 68 | struct v4l2_mbus_framefmt *format; |
69 | struct v4l2_rect *crop; | 69 | int ret = 0; |
70 | |||
71 | mutex_lock(&rwpf->entity.lock); | ||
70 | 72 | ||
71 | config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fmt->which); | 73 | config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fmt->which); |
72 | if (!config) | 74 | if (!config) { |
73 | return -EINVAL; | 75 | ret = -EINVAL; |
76 | goto done; | ||
77 | } | ||
74 | 78 | ||
75 | /* Default to YUV if the requested format is not supported. */ | 79 | /* Default to YUV if the requested format is not supported. */ |
76 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && | 80 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && |
@@ -85,7 +89,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, | |||
85 | */ | 89 | */ |
86 | format->code = fmt->format.code; | 90 | format->code = fmt->format.code; |
87 | fmt->format = *format; | 91 | fmt->format = *format; |
88 | return 0; | 92 | goto done; |
89 | } | 93 | } |
90 | 94 | ||
91 | format->code = fmt->format.code; | 95 | format->code = fmt->format.code; |
@@ -98,19 +102,25 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, | |||
98 | 102 | ||
99 | fmt->format = *format; | 103 | fmt->format = *format; |
100 | 104 | ||
101 | /* Update the sink crop rectangle. */ | 105 | if (rwpf->entity.type == VSP1_ENTITY_RPF) { |
102 | crop = vsp1_rwpf_get_crop(rwpf, config); | 106 | struct v4l2_rect *crop; |
103 | crop->left = 0; | 107 | |
104 | crop->top = 0; | 108 | /* Update the sink crop rectangle. */ |
105 | crop->width = fmt->format.width; | 109 | crop = vsp1_rwpf_get_crop(rwpf, config); |
106 | crop->height = fmt->format.height; | 110 | crop->left = 0; |
111 | crop->top = 0; | ||
112 | crop->width = fmt->format.width; | ||
113 | crop->height = fmt->format.height; | ||
114 | } | ||
107 | 115 | ||
108 | /* Propagate the format to the source pad. */ | 116 | /* Propagate the format to the source pad. */ |
109 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, | 117 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, |
110 | RWPF_PAD_SOURCE); | 118 | RWPF_PAD_SOURCE); |
111 | *format = fmt->format; | 119 | *format = fmt->format; |
112 | 120 | ||
113 | return 0; | 121 | done: |
122 | mutex_unlock(&rwpf->entity.lock); | ||
123 | return ret; | ||
114 | } | 124 | } |
115 | 125 | ||
116 | static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, | 126 | static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, |
@@ -120,14 +130,22 @@ static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, | |||
120 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); | 130 | struct vsp1_rwpf *rwpf = to_rwpf(subdev); |
121 | struct v4l2_subdev_pad_config *config; | 131 | struct v4l2_subdev_pad_config *config; |
122 | struct v4l2_mbus_framefmt *format; | 132 | struct v4l2_mbus_framefmt *format; |
133 | int ret = 0; | ||
123 | 134 | ||
124 | /* Cropping is implemented on the sink pad. */ | 135 | /* |
125 | if (sel->pad != RWPF_PAD_SINK) | 136 | * Cropping is only supported on the RPF and is implemented on the sink |
137 | * pad. | ||
138 | */ | ||
139 | if (rwpf->entity.type == VSP1_ENTITY_WPF || sel->pad != RWPF_PAD_SINK) | ||
126 | return -EINVAL; | 140 | return -EINVAL; |
127 | 141 | ||
142 | mutex_lock(&rwpf->entity.lock); | ||
143 | |||
128 | config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which); | 144 | config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which); |
129 | if (!config) | 145 | if (!config) { |
130 | return -EINVAL; | 146 | ret = -EINVAL; |
147 | goto done; | ||
148 | } | ||
131 | 149 | ||
132 | switch (sel->target) { | 150 | switch (sel->target) { |
133 | case V4L2_SEL_TGT_CROP: | 151 | case V4L2_SEL_TGT_CROP: |
@@ -144,10 +162,13 @@ static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, | |||
144 | break; | 162 | break; |
145 | 163 | ||
146 | default: | 164 | default: |
147 | return -EINVAL; | 165 | ret = -EINVAL; |
166 | break; | ||
148 | } | 167 | } |
149 | 168 | ||
150 | return 0; | 169 | done: |
170 | mutex_unlock(&rwpf->entity.lock); | ||
171 | return ret; | ||
151 | } | 172 | } |
152 | 173 | ||
153 | static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | 174 | static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, |
@@ -158,21 +179,27 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | |||
158 | struct v4l2_subdev_pad_config *config; | 179 | struct v4l2_subdev_pad_config *config; |
159 | struct v4l2_mbus_framefmt *format; | 180 | struct v4l2_mbus_framefmt *format; |
160 | struct v4l2_rect *crop; | 181 | struct v4l2_rect *crop; |
182 | int ret = 0; | ||
161 | 183 | ||
162 | /* Cropping is implemented on the sink pad. */ | 184 | /* |
163 | if (sel->pad != RWPF_PAD_SINK) | 185 | * Cropping is only supported on the RPF and is implemented on the sink |
186 | * pad. | ||
187 | */ | ||
188 | if (rwpf->entity.type == VSP1_ENTITY_WPF || sel->pad != RWPF_PAD_SINK) | ||
164 | return -EINVAL; | 189 | return -EINVAL; |
165 | 190 | ||
166 | if (sel->target != V4L2_SEL_TGT_CROP) | 191 | if (sel->target != V4L2_SEL_TGT_CROP) |
167 | return -EINVAL; | 192 | return -EINVAL; |
168 | 193 | ||
194 | mutex_lock(&rwpf->entity.lock); | ||
195 | |||
169 | config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which); | 196 | config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which); |
170 | if (!config) | 197 | if (!config) { |
171 | return -EINVAL; | 198 | ret = -EINVAL; |
199 | goto done; | ||
200 | } | ||
172 | 201 | ||
173 | /* Make sure the crop rectangle is entirely contained in the image. The | 202 | /* Make sure the crop rectangle is entirely contained in the image. */ |
174 | * WPF top and left offsets are limited to 255. | ||
175 | */ | ||
176 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, | 203 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, |
177 | RWPF_PAD_SINK); | 204 | RWPF_PAD_SINK); |
178 | 205 | ||
@@ -188,10 +215,6 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | |||
188 | 215 | ||
189 | sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); | 216 | sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); |
190 | sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); | 217 | sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); |
191 | if (rwpf->entity.type == VSP1_ENTITY_WPF) { | ||
192 | sel->r.left = min_t(unsigned int, sel->r.left, 255); | ||
193 | sel->r.top = min_t(unsigned int, sel->r.top, 255); | ||
194 | } | ||
195 | sel->r.width = min_t(unsigned int, sel->r.width, | 218 | sel->r.width = min_t(unsigned int, sel->r.width, |
196 | format->width - sel->r.left); | 219 | format->width - sel->r.left); |
197 | sel->r.height = min_t(unsigned int, sel->r.height, | 220 | sel->r.height = min_t(unsigned int, sel->r.height, |
@@ -206,7 +229,9 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | |||
206 | format->width = crop->width; | 229 | format->width = crop->width; |
207 | format->height = crop->height; | 230 | format->height = crop->height; |
208 | 231 | ||
209 | return 0; | 232 | done: |
233 | mutex_unlock(&rwpf->entity.lock); | ||
234 | return ret; | ||
210 | } | 235 | } |
211 | 236 | ||
212 | const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = { | 237 | const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = { |
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index cb20484e80da..1c98aff3da5d 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h | |||
@@ -61,7 +61,6 @@ struct vsp1_rwpf { | |||
61 | unsigned int active; | 61 | unsigned int active; |
62 | } flip; | 62 | } flip; |
63 | 63 | ||
64 | unsigned int offsets[2]; | ||
65 | struct vsp1_rwpf_memory mem; | 64 | struct vsp1_rwpf_memory mem; |
66 | 65 | ||
67 | struct vsp1_dl_manager *dlm; | 66 | struct vsp1_dl_manager *dlm; |
@@ -86,17 +85,5 @@ extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops; | |||
86 | 85 | ||
87 | struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, | 86 | struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, |
88 | struct v4l2_subdev_pad_config *config); | 87 | struct v4l2_subdev_pad_config *config); |
89 | /** | ||
90 | * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF | ||
91 | * @rwpf: the [RW]PF instance | ||
92 | * @dl: the display list | ||
93 | * | ||
94 | * This function applies the cached memory buffer address to the display list. | ||
95 | */ | ||
96 | static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf, | ||
97 | struct vsp1_dl_list *dl) | ||
98 | { | ||
99 | rwpf->entity.ops->set_memory(&rwpf->entity, dl); | ||
100 | } | ||
101 | 88 | ||
102 | #endif /* __VSP1_RWPF_H__ */ | 89 | #endif /* __VSP1_RWPF_H__ */ |
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index 47f5e0cea2ce..b4e568a3b4ed 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c | |||
@@ -128,6 +128,7 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev, | |||
128 | struct vsp1_sru *sru = to_sru(subdev); | 128 | struct vsp1_sru *sru = to_sru(subdev); |
129 | struct v4l2_subdev_pad_config *config; | 129 | struct v4l2_subdev_pad_config *config; |
130 | struct v4l2_mbus_framefmt *format; | 130 | struct v4l2_mbus_framefmt *format; |
131 | int ret = 0; | ||
131 | 132 | ||
132 | config = vsp1_entity_get_pad_config(&sru->entity, cfg, fse->which); | 133 | config = vsp1_entity_get_pad_config(&sru->entity, cfg, fse->which); |
133 | if (!config) | 134 | if (!config) |
@@ -135,8 +136,12 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev, | |||
135 | 136 | ||
136 | format = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK); | 137 | format = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK); |
137 | 138 | ||
138 | if (fse->index || fse->code != format->code) | 139 | mutex_lock(&sru->entity.lock); |
139 | return -EINVAL; | 140 | |
141 | if (fse->index || fse->code != format->code) { | ||
142 | ret = -EINVAL; | ||
143 | goto done; | ||
144 | } | ||
140 | 145 | ||
141 | if (fse->pad == SRU_PAD_SINK) { | 146 | if (fse->pad == SRU_PAD_SINK) { |
142 | fse->min_width = SRU_MIN_SIZE; | 147 | fse->min_width = SRU_MIN_SIZE; |
@@ -156,7 +161,9 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev, | |||
156 | } | 161 | } |
157 | } | 162 | } |
158 | 163 | ||
159 | return 0; | 164 | done: |
165 | mutex_unlock(&sru->entity.lock); | ||
166 | return ret; | ||
160 | } | 167 | } |
161 | 168 | ||
162 | static void sru_try_format(struct vsp1_sru *sru, | 169 | static void sru_try_format(struct vsp1_sru *sru, |
@@ -217,10 +224,15 @@ static int sru_set_format(struct v4l2_subdev *subdev, | |||
217 | struct vsp1_sru *sru = to_sru(subdev); | 224 | struct vsp1_sru *sru = to_sru(subdev); |
218 | struct v4l2_subdev_pad_config *config; | 225 | struct v4l2_subdev_pad_config *config; |
219 | struct v4l2_mbus_framefmt *format; | 226 | struct v4l2_mbus_framefmt *format; |
227 | int ret = 0; | ||
228 | |||
229 | mutex_lock(&sru->entity.lock); | ||
220 | 230 | ||
221 | config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which); | 231 | config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which); |
222 | if (!config) | 232 | if (!config) { |
223 | return -EINVAL; | 233 | ret = -EINVAL; |
234 | goto done; | ||
235 | } | ||
224 | 236 | ||
225 | sru_try_format(sru, config, fmt->pad, &fmt->format); | 237 | sru_try_format(sru, config, fmt->pad, &fmt->format); |
226 | 238 | ||
@@ -236,7 +248,9 @@ static int sru_set_format(struct v4l2_subdev *subdev, | |||
236 | sru_try_format(sru, config, SRU_PAD_SOURCE, format); | 248 | sru_try_format(sru, config, SRU_PAD_SOURCE, format); |
237 | } | 249 | } |
238 | 250 | ||
239 | return 0; | 251 | done: |
252 | mutex_unlock(&sru->entity.lock); | ||
253 | return ret; | ||
240 | } | 254 | } |
241 | 255 | ||
242 | static const struct v4l2_subdev_pad_ops sru_pad_ops = { | 256 | static const struct v4l2_subdev_pad_ops sru_pad_ops = { |
@@ -257,7 +271,8 @@ static const struct v4l2_subdev_ops sru_ops = { | |||
257 | 271 | ||
258 | static void sru_configure(struct vsp1_entity *entity, | 272 | static void sru_configure(struct vsp1_entity *entity, |
259 | struct vsp1_pipeline *pipe, | 273 | struct vsp1_pipeline *pipe, |
260 | struct vsp1_dl_list *dl, bool full) | 274 | struct vsp1_dl_list *dl, |
275 | enum vsp1_entity_params params) | ||
261 | { | 276 | { |
262 | const struct vsp1_sru_param *param; | 277 | const struct vsp1_sru_param *param; |
263 | struct vsp1_sru *sru = to_sru(&entity->subdev); | 278 | struct vsp1_sru *sru = to_sru(&entity->subdev); |
@@ -265,7 +280,7 @@ static void sru_configure(struct vsp1_entity *entity, | |||
265 | struct v4l2_mbus_framefmt *output; | 280 | struct v4l2_mbus_framefmt *output; |
266 | u32 ctrl0; | 281 | u32 ctrl0; |
267 | 282 | ||
268 | if (!full) | 283 | if (params != VSP1_ENTITY_PARAMS_INIT) |
269 | return; | 284 | return; |
270 | 285 | ||
271 | input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, | 286 | input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, |
@@ -291,8 +306,27 @@ static void sru_configure(struct vsp1_entity *entity, | |||
291 | vsp1_sru_write(sru, dl, VI6_SRU_CTRL2, param->ctrl2); | 306 | vsp1_sru_write(sru, dl, VI6_SRU_CTRL2, param->ctrl2); |
292 | } | 307 | } |
293 | 308 | ||
309 | static unsigned int sru_max_width(struct vsp1_entity *entity, | ||
310 | struct vsp1_pipeline *pipe) | ||
311 | { | ||
312 | struct vsp1_sru *sru = to_sru(&entity->subdev); | ||
313 | struct v4l2_mbus_framefmt *input; | ||
314 | struct v4l2_mbus_framefmt *output; | ||
315 | |||
316 | input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, | ||
317 | SRU_PAD_SINK); | ||
318 | output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, | ||
319 | SRU_PAD_SOURCE); | ||
320 | |||
321 | if (input->width != output->width) | ||
322 | return 512; | ||
323 | else | ||
324 | return 256; | ||
325 | } | ||
326 | |||
294 | static const struct vsp1_entity_operations sru_entity_ops = { | 327 | static const struct vsp1_entity_operations sru_entity_ops = { |
295 | .configure = sru_configure, | 328 | .configure = sru_configure, |
329 | .max_width = sru_max_width, | ||
296 | }; | 330 | }; |
297 | 331 | ||
298 | /* ----------------------------------------------------------------------------- | 332 | /* ----------------------------------------------------------------------------- |
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index 652dcd895022..da8f89a31ea4 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include "vsp1.h" | 19 | #include "vsp1.h" |
20 | #include "vsp1_dl.h" | 20 | #include "vsp1_dl.h" |
21 | #include "vsp1_pipe.h" | ||
21 | #include "vsp1_uds.h" | 22 | #include "vsp1_uds.h" |
22 | 23 | ||
23 | #define UDS_MIN_SIZE 4U | 24 | #define UDS_MIN_SIZE 4U |
@@ -133,6 +134,7 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev, | |||
133 | struct vsp1_uds *uds = to_uds(subdev); | 134 | struct vsp1_uds *uds = to_uds(subdev); |
134 | struct v4l2_subdev_pad_config *config; | 135 | struct v4l2_subdev_pad_config *config; |
135 | struct v4l2_mbus_framefmt *format; | 136 | struct v4l2_mbus_framefmt *format; |
137 | int ret = 0; | ||
136 | 138 | ||
137 | config = vsp1_entity_get_pad_config(&uds->entity, cfg, fse->which); | 139 | config = vsp1_entity_get_pad_config(&uds->entity, cfg, fse->which); |
138 | if (!config) | 140 | if (!config) |
@@ -141,8 +143,12 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev, | |||
141 | format = vsp1_entity_get_pad_format(&uds->entity, config, | 143 | format = vsp1_entity_get_pad_format(&uds->entity, config, |
142 | UDS_PAD_SINK); | 144 | UDS_PAD_SINK); |
143 | 145 | ||
144 | if (fse->index || fse->code != format->code) | 146 | mutex_lock(&uds->entity.lock); |
145 | return -EINVAL; | 147 | |
148 | if (fse->index || fse->code != format->code) { | ||
149 | ret = -EINVAL; | ||
150 | goto done; | ||
151 | } | ||
146 | 152 | ||
147 | if (fse->pad == UDS_PAD_SINK) { | 153 | if (fse->pad == UDS_PAD_SINK) { |
148 | fse->min_width = UDS_MIN_SIZE; | 154 | fse->min_width = UDS_MIN_SIZE; |
@@ -156,7 +162,9 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev, | |||
156 | &fse->max_height); | 162 | &fse->max_height); |
157 | } | 163 | } |
158 | 164 | ||
159 | return 0; | 165 | done: |
166 | mutex_unlock(&uds->entity.lock); | ||
167 | return ret; | ||
160 | } | 168 | } |
161 | 169 | ||
162 | static void uds_try_format(struct vsp1_uds *uds, | 170 | static void uds_try_format(struct vsp1_uds *uds, |
@@ -202,10 +210,15 @@ static int uds_set_format(struct v4l2_subdev *subdev, | |||
202 | struct vsp1_uds *uds = to_uds(subdev); | 210 | struct vsp1_uds *uds = to_uds(subdev); |
203 | struct v4l2_subdev_pad_config *config; | 211 | struct v4l2_subdev_pad_config *config; |
204 | struct v4l2_mbus_framefmt *format; | 212 | struct v4l2_mbus_framefmt *format; |
213 | int ret = 0; | ||
214 | |||
215 | mutex_lock(&uds->entity.lock); | ||
205 | 216 | ||
206 | config = vsp1_entity_get_pad_config(&uds->entity, cfg, fmt->which); | 217 | config = vsp1_entity_get_pad_config(&uds->entity, cfg, fmt->which); |
207 | if (!config) | 218 | if (!config) { |
208 | return -EINVAL; | 219 | ret = -EINVAL; |
220 | goto done; | ||
221 | } | ||
209 | 222 | ||
210 | uds_try_format(uds, config, fmt->pad, &fmt->format); | 223 | uds_try_format(uds, config, fmt->pad, &fmt->format); |
211 | 224 | ||
@@ -221,7 +234,9 @@ static int uds_set_format(struct v4l2_subdev *subdev, | |||
221 | uds_try_format(uds, config, UDS_PAD_SOURCE, format); | 234 | uds_try_format(uds, config, UDS_PAD_SOURCE, format); |
222 | } | 235 | } |
223 | 236 | ||
224 | return 0; | 237 | done: |
238 | mutex_unlock(&uds->entity.lock); | ||
239 | return ret; | ||
225 | } | 240 | } |
226 | 241 | ||
227 | /* ----------------------------------------------------------------------------- | 242 | /* ----------------------------------------------------------------------------- |
@@ -246,7 +261,8 @@ static const struct v4l2_subdev_ops uds_ops = { | |||
246 | 261 | ||
247 | static void uds_configure(struct vsp1_entity *entity, | 262 | static void uds_configure(struct vsp1_entity *entity, |
248 | struct vsp1_pipeline *pipe, | 263 | struct vsp1_pipeline *pipe, |
249 | struct vsp1_dl_list *dl, bool full) | 264 | struct vsp1_dl_list *dl, |
265 | enum vsp1_entity_params params) | ||
250 | { | 266 | { |
251 | struct vsp1_uds *uds = to_uds(&entity->subdev); | 267 | struct vsp1_uds *uds = to_uds(&entity->subdev); |
252 | const struct v4l2_mbus_framefmt *output; | 268 | const struct v4l2_mbus_framefmt *output; |
@@ -255,7 +271,16 @@ static void uds_configure(struct vsp1_entity *entity, | |||
255 | unsigned int vscale; | 271 | unsigned int vscale; |
256 | bool multitap; | 272 | bool multitap; |
257 | 273 | ||
258 | if (!full) | 274 | if (params == VSP1_ENTITY_PARAMS_PARTITION) { |
275 | const struct v4l2_rect *clip = &pipe->partition; | ||
276 | |||
277 | vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE, | ||
278 | (clip->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | | ||
279 | (clip->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); | ||
280 | return; | ||
281 | } | ||
282 | |||
283 | if (params != VSP1_ENTITY_PARAMS_INIT) | ||
259 | return; | 284 | return; |
260 | 285 | ||
261 | input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, | 286 | input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, |
@@ -287,17 +312,39 @@ static void uds_configure(struct vsp1_entity *entity, | |||
287 | (uds_passband_width(vscale) | 312 | (uds_passband_width(vscale) |
288 | << VI6_UDS_PASS_BWIDTH_V_SHIFT)); | 313 | << VI6_UDS_PASS_BWIDTH_V_SHIFT)); |
289 | 314 | ||
290 | /* Set the scaling ratios and the output size. */ | 315 | /* Set the scaling ratios. */ |
291 | vsp1_uds_write(uds, dl, VI6_UDS_SCALE, | 316 | vsp1_uds_write(uds, dl, VI6_UDS_SCALE, |
292 | (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) | | 317 | (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) | |
293 | (vscale << VI6_UDS_SCALE_VFRAC_SHIFT)); | 318 | (vscale << VI6_UDS_SCALE_VFRAC_SHIFT)); |
294 | vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE, | 319 | } |
295 | (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | | 320 | |
296 | (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); | 321 | static unsigned int uds_max_width(struct vsp1_entity *entity, |
322 | struct vsp1_pipeline *pipe) | ||
323 | { | ||
324 | struct vsp1_uds *uds = to_uds(&entity->subdev); | ||
325 | const struct v4l2_mbus_framefmt *output; | ||
326 | const struct v4l2_mbus_framefmt *input; | ||
327 | unsigned int hscale; | ||
328 | |||
329 | input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, | ||
330 | UDS_PAD_SINK); | ||
331 | output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, | ||
332 | UDS_PAD_SOURCE); | ||
333 | hscale = output->width / input->width; | ||
334 | |||
335 | if (hscale <= 2) | ||
336 | return 256; | ||
337 | else if (hscale <= 4) | ||
338 | return 512; | ||
339 | else if (hscale <= 8) | ||
340 | return 1024; | ||
341 | else | ||
342 | return 2048; | ||
297 | } | 343 | } |
298 | 344 | ||
299 | static const struct vsp1_entity_operations uds_entity_ops = { | 345 | static const struct vsp1_entity_operations uds_entity_ops = { |
300 | .configure = uds_configure, | 346 | .configure = uds_configure, |
347 | .max_width = uds_max_width, | ||
301 | }; | 348 | }; |
302 | 349 | ||
303 | /* ----------------------------------------------------------------------------- | 350 | /* ----------------------------------------------------------------------------- |
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 9fb4fc26a359..d351b9c768d2 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c | |||
@@ -117,9 +117,9 @@ static int __vsp1_video_try_format(struct vsp1_video *video, | |||
117 | /* Retrieve format information and select the default format if the | 117 | /* Retrieve format information and select the default format if the |
118 | * requested format isn't supported. | 118 | * requested format isn't supported. |
119 | */ | 119 | */ |
120 | info = vsp1_get_format_info(pix->pixelformat); | 120 | info = vsp1_get_format_info(video->vsp1, pix->pixelformat); |
121 | if (info == NULL) | 121 | if (info == NULL) |
122 | info = vsp1_get_format_info(VSP1_VIDEO_DEF_FORMAT); | 122 | info = vsp1_get_format_info(video->vsp1, VSP1_VIDEO_DEF_FORMAT); |
123 | 123 | ||
124 | pix->pixelformat = info->fourcc; | 124 | pix->pixelformat = info->fourcc; |
125 | pix->colorspace = V4L2_COLORSPACE_SRGB; | 125 | pix->colorspace = V4L2_COLORSPACE_SRGB; |
@@ -169,6 +169,113 @@ static int __vsp1_video_try_format(struct vsp1_video *video, | |||
169 | } | 169 | } |
170 | 170 | ||
171 | /* ----------------------------------------------------------------------------- | 171 | /* ----------------------------------------------------------------------------- |
172 | * VSP1 Partition Algorithm support | ||
173 | */ | ||
174 | |||
175 | static void vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe) | ||
176 | { | ||
177 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; | ||
178 | const struct v4l2_mbus_framefmt *format; | ||
179 | struct vsp1_entity *entity; | ||
180 | unsigned int div_size; | ||
181 | |||
182 | format = vsp1_entity_get_pad_format(&pipe->output->entity, | ||
183 | pipe->output->entity.config, | ||
184 | RWPF_PAD_SOURCE); | ||
185 | div_size = format->width; | ||
186 | |||
187 | /* Gen2 hardware doesn't require image partitioning. */ | ||
188 | if (vsp1->info->gen == 2) { | ||
189 | pipe->div_size = div_size; | ||
190 | pipe->partitions = 1; | ||
191 | return; | ||
192 | } | ||
193 | |||
194 | list_for_each_entry(entity, &pipe->entities, list_pipe) { | ||
195 | unsigned int entity_max = VSP1_VIDEO_MAX_WIDTH; | ||
196 | |||
197 | if (entity->ops->max_width) { | ||
198 | entity_max = entity->ops->max_width(entity, pipe); | ||
199 | if (entity_max) | ||
200 | div_size = min(div_size, entity_max); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | pipe->div_size = div_size; | ||
205 | pipe->partitions = DIV_ROUND_UP(format->width, div_size); | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * vsp1_video_partition - Calculate the active partition output window | ||
210 | * | ||
211 | * @div_size: pre-determined maximum partition division size | ||
212 | * @index: partition index | ||
213 | * | ||
214 | * Returns a v4l2_rect describing the partition window. | ||
215 | */ | ||
216 | static struct v4l2_rect vsp1_video_partition(struct vsp1_pipeline *pipe, | ||
217 | unsigned int div_size, | ||
218 | unsigned int index) | ||
219 | { | ||
220 | const struct v4l2_mbus_framefmt *format; | ||
221 | struct v4l2_rect partition; | ||
222 | unsigned int modulus; | ||
223 | |||
224 | format = vsp1_entity_get_pad_format(&pipe->output->entity, | ||
225 | pipe->output->entity.config, | ||
226 | RWPF_PAD_SOURCE); | ||
227 | |||
228 | /* A single partition simply processes the output size in full. */ | ||
229 | if (pipe->partitions <= 1) { | ||
230 | partition.left = 0; | ||
231 | partition.top = 0; | ||
232 | partition.width = format->width; | ||
233 | partition.height = format->height; | ||
234 | return partition; | ||
235 | } | ||
236 | |||
237 | /* Initialise the partition with sane starting conditions. */ | ||
238 | partition.left = index * div_size; | ||
239 | partition.top = 0; | ||
240 | partition.width = div_size; | ||
241 | partition.height = format->height; | ||
242 | |||
243 | modulus = format->width % div_size; | ||
244 | |||
245 | /* | ||
246 | * We need to prevent the last partition from being smaller than the | ||
247 | * *minimum* width of the hardware capabilities. | ||
248 | * | ||
249 | * If the modulus is less than half of the partition size, | ||
250 | * the penultimate partition is reduced to half, which is added | ||
251 | * to the final partition: |1234|1234|1234|12|341| | ||
252 | * to prevents this: |1234|1234|1234|1234|1|. | ||
253 | */ | ||
254 | if (modulus) { | ||
255 | /* | ||
256 | * pipe->partitions is 1 based, whilst index is a 0 based index. | ||
257 | * Normalise this locally. | ||
258 | */ | ||
259 | unsigned int partitions = pipe->partitions - 1; | ||
260 | |||
261 | if (modulus < div_size / 2) { | ||
262 | if (index == partitions - 1) { | ||
263 | /* Halve the penultimate partition. */ | ||
264 | partition.width = div_size / 2; | ||
265 | } else if (index == partitions) { | ||
266 | /* Increase the final partition. */ | ||
267 | partition.width = (div_size / 2) + modulus; | ||
268 | partition.left -= div_size / 2; | ||
269 | } | ||
270 | } else if (index == partitions) { | ||
271 | partition.width = modulus; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | return partition; | ||
276 | } | ||
277 | |||
278 | /* ----------------------------------------------------------------------------- | ||
172 | * Pipeline Management | 279 | * Pipeline Management |
173 | */ | 280 | */ |
174 | 281 | ||
@@ -234,44 +341,81 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe, | |||
234 | { | 341 | { |
235 | struct vsp1_video *video = rwpf->video; | 342 | struct vsp1_video *video = rwpf->video; |
236 | struct vsp1_vb2_buffer *buf; | 343 | struct vsp1_vb2_buffer *buf; |
237 | unsigned long flags; | ||
238 | 344 | ||
239 | buf = vsp1_video_complete_buffer(video); | 345 | buf = vsp1_video_complete_buffer(video); |
240 | if (buf == NULL) | 346 | if (buf == NULL) |
241 | return; | 347 | return; |
242 | 348 | ||
243 | spin_lock_irqsave(&pipe->irqlock, flags); | ||
244 | |||
245 | video->rwpf->mem = buf->mem; | 349 | video->rwpf->mem = buf->mem; |
246 | pipe->buffers_ready |= 1 << video->pipe_index; | 350 | pipe->buffers_ready |= 1 << video->pipe_index; |
351 | } | ||
247 | 352 | ||
248 | spin_unlock_irqrestore(&pipe->irqlock, flags); | 353 | static void vsp1_video_pipeline_run_partition(struct vsp1_pipeline *pipe, |
354 | struct vsp1_dl_list *dl) | ||
355 | { | ||
356 | struct vsp1_entity *entity; | ||
357 | |||
358 | pipe->partition = vsp1_video_partition(pipe, pipe->div_size, | ||
359 | pipe->current_partition); | ||
360 | |||
361 | list_for_each_entry(entity, &pipe->entities, list_pipe) { | ||
362 | if (entity->ops->configure) | ||
363 | entity->ops->configure(entity, pipe, dl, | ||
364 | VSP1_ENTITY_PARAMS_PARTITION); | ||
365 | } | ||
249 | } | 366 | } |
250 | 367 | ||
251 | static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) | 368 | static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) |
252 | { | 369 | { |
253 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; | 370 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; |
254 | struct vsp1_entity *entity; | 371 | struct vsp1_entity *entity; |
255 | unsigned int i; | ||
256 | 372 | ||
257 | if (!pipe->dl) | 373 | if (!pipe->dl) |
258 | pipe->dl = vsp1_dl_list_get(pipe->output->dlm); | 374 | pipe->dl = vsp1_dl_list_get(pipe->output->dlm); |
259 | 375 | ||
376 | /* | ||
377 | * Start with the runtime parameters as the configure operation can | ||
378 | * compute/cache information needed when configuring partitions. This | ||
379 | * is the case with flipping in the WPF. | ||
380 | */ | ||
260 | list_for_each_entry(entity, &pipe->entities, list_pipe) { | 381 | list_for_each_entry(entity, &pipe->entities, list_pipe) { |
261 | if (entity->ops->configure) | 382 | if (entity->ops->configure) |
262 | entity->ops->configure(entity, pipe, pipe->dl, false); | 383 | entity->ops->configure(entity, pipe, pipe->dl, |
384 | VSP1_ENTITY_PARAMS_RUNTIME); | ||
263 | } | 385 | } |
264 | 386 | ||
265 | for (i = 0; i < vsp1->info->rpf_count; ++i) { | 387 | /* Run the first partition */ |
266 | struct vsp1_rwpf *rwpf = pipe->inputs[i]; | 388 | pipe->current_partition = 0; |
389 | vsp1_video_pipeline_run_partition(pipe, pipe->dl); | ||
267 | 390 | ||
268 | if (rwpf) | 391 | /* Process consecutive partitions as necessary */ |
269 | vsp1_rwpf_set_memory(rwpf, pipe->dl); | 392 | for (pipe->current_partition = 1; |
270 | } | 393 | pipe->current_partition < pipe->partitions; |
394 | pipe->current_partition++) { | ||
395 | struct vsp1_dl_list *dl; | ||
271 | 396 | ||
272 | if (!pipe->lif) | 397 | /* |
273 | vsp1_rwpf_set_memory(pipe->output, pipe->dl); | 398 | * Partition configuration operations will utilise |
399 | * the pipe->current_partition variable to determine | ||
400 | * the work they should complete. | ||
401 | */ | ||
402 | dl = vsp1_dl_list_get(pipe->output->dlm); | ||
403 | |||
404 | /* | ||
405 | * An incomplete chain will still function, but output only | ||
406 | * the partitions that had a dl available. The frame end | ||
407 | * interrupt will be marked on the last dl in the chain. | ||
408 | */ | ||
409 | if (!dl) { | ||
410 | dev_err(vsp1->dev, "Failed to obtain a dl list. Frame will be incomplete\n"); | ||
411 | break; | ||
412 | } | ||
413 | |||
414 | vsp1_video_pipeline_run_partition(pipe, dl); | ||
415 | vsp1_dl_list_add_chain(pipe->dl, dl); | ||
416 | } | ||
274 | 417 | ||
418 | /* Complete, and commit the head display list. */ | ||
275 | vsp1_dl_list_commit(pipe->dl); | 419 | vsp1_dl_list_commit(pipe->dl); |
276 | pipe->dl = NULL; | 420 | pipe->dl = NULL; |
277 | 421 | ||
@@ -285,6 +429,8 @@ static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe) | |||
285 | unsigned long flags; | 429 | unsigned long flags; |
286 | unsigned int i; | 430 | unsigned int i; |
287 | 431 | ||
432 | spin_lock_irqsave(&pipe->irqlock, flags); | ||
433 | |||
288 | /* Complete buffers on all video nodes. */ | 434 | /* Complete buffers on all video nodes. */ |
289 | for (i = 0; i < vsp1->info->rpf_count; ++i) { | 435 | for (i = 0; i < vsp1->info->rpf_count; ++i) { |
290 | if (!pipe->inputs[i]) | 436 | if (!pipe->inputs[i]) |
@@ -295,8 +441,6 @@ static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe) | |||
295 | 441 | ||
296 | vsp1_video_frame_end(pipe, pipe->output); | 442 | vsp1_video_frame_end(pipe, pipe->output); |
297 | 443 | ||
298 | spin_lock_irqsave(&pipe->irqlock, flags); | ||
299 | |||
300 | state = pipe->state; | 444 | state = pipe->state; |
301 | pipe->state = VSP1_PIPELINE_STOPPED; | 445 | pipe->state = VSP1_PIPELINE_STOPPED; |
302 | 446 | ||
@@ -607,6 +751,9 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) | |||
607 | { | 751 | { |
608 | struct vsp1_entity *entity; | 752 | struct vsp1_entity *entity; |
609 | 753 | ||
754 | /* Determine this pipelines sizes for image partitioning support. */ | ||
755 | vsp1_video_pipeline_setup_partitions(pipe); | ||
756 | |||
610 | /* Prepare the display list. */ | 757 | /* Prepare the display list. */ |
611 | pipe->dl = vsp1_dl_list_get(pipe->output->dlm); | 758 | pipe->dl = vsp1_dl_list_get(pipe->output->dlm); |
612 | if (!pipe->dl) | 759 | if (!pipe->dl) |
@@ -634,7 +781,8 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) | |||
634 | vsp1_entity_route_setup(entity, pipe->dl); | 781 | vsp1_entity_route_setup(entity, pipe->dl); |
635 | 782 | ||
636 | if (entity->ops->configure) | 783 | if (entity->ops->configure) |
637 | entity->ops->configure(entity, pipe, pipe->dl, true); | 784 | entity->ops->configure(entity, pipe, pipe->dl, |
785 | VSP1_ENTITY_PARAMS_INIT); | ||
638 | } | 786 | } |
639 | 787 | ||
640 | return 0; | 788 | return 0; |
@@ -675,6 +823,14 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq) | |||
675 | unsigned long flags; | 823 | unsigned long flags; |
676 | int ret; | 824 | int ret; |
677 | 825 | ||
826 | /* | ||
827 | * Clear the buffers ready flag to make sure the device won't be started | ||
828 | * by a QBUF on the video node on the other side of the pipeline. | ||
829 | */ | ||
830 | spin_lock_irqsave(&video->irqlock, flags); | ||
831 | pipe->buffers_ready &= ~(1 << video->pipe_index); | ||
832 | spin_unlock_irqrestore(&video->irqlock, flags); | ||
833 | |||
678 | mutex_lock(&pipe->lock); | 834 | mutex_lock(&pipe->lock); |
679 | if (--pipe->stream_count == pipe->num_inputs) { | 835 | if (--pipe->stream_count == pipe->num_inputs) { |
680 | /* Stop the pipeline. */ | 836 | /* Stop the pipeline. */ |
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 31983169c24a..7c48f81cd5c1 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c | |||
@@ -173,58 +173,28 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity) | |||
173 | vsp1_dlm_destroy(wpf->dlm); | 173 | vsp1_dlm_destroy(wpf->dlm); |
174 | } | 174 | } |
175 | 175 | ||
176 | static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) | ||
177 | { | ||
178 | struct vsp1_rwpf *wpf = entity_to_rwpf(entity); | ||
179 | const struct v4l2_pix_format_mplane *format = &wpf->format; | ||
180 | struct vsp1_rwpf_memory mem = wpf->mem; | ||
181 | unsigned int flip = wpf->flip.active; | ||
182 | unsigned int offset; | ||
183 | |||
184 | /* Update the memory offsets based on flipping configuration. The | ||
185 | * destination addresses point to the locations where the VSP starts | ||
186 | * writing to memory, which can be different corners of the image | ||
187 | * depending on vertical flipping. Horizontal flipping is handled | ||
188 | * through a line buffer and doesn't modify the start address. | ||
189 | */ | ||
190 | if (flip & BIT(WPF_CTRL_VFLIP)) { | ||
191 | mem.addr[0] += (format->height - 1) | ||
192 | * format->plane_fmt[0].bytesperline; | ||
193 | |||
194 | if (format->num_planes > 1) { | ||
195 | offset = (format->height / wpf->fmtinfo->vsub - 1) | ||
196 | * format->plane_fmt[1].bytesperline; | ||
197 | mem.addr[1] += offset; | ||
198 | mem.addr[2] += offset; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]); | ||
203 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]); | ||
204 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]); | ||
205 | } | ||
206 | |||
207 | static void wpf_configure(struct vsp1_entity *entity, | 176 | static void wpf_configure(struct vsp1_entity *entity, |
208 | struct vsp1_pipeline *pipe, | 177 | struct vsp1_pipeline *pipe, |
209 | struct vsp1_dl_list *dl, bool full) | 178 | struct vsp1_dl_list *dl, |
179 | enum vsp1_entity_params params) | ||
210 | { | 180 | { |
211 | struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); | 181 | struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); |
212 | struct vsp1_device *vsp1 = wpf->entity.vsp1; | 182 | struct vsp1_device *vsp1 = wpf->entity.vsp1; |
213 | const struct v4l2_mbus_framefmt *source_format; | 183 | const struct v4l2_mbus_framefmt *source_format; |
214 | const struct v4l2_mbus_framefmt *sink_format; | 184 | const struct v4l2_mbus_framefmt *sink_format; |
215 | const struct v4l2_rect *crop; | ||
216 | unsigned int i; | 185 | unsigned int i; |
217 | u32 outfmt = 0; | 186 | u32 outfmt = 0; |
218 | u32 srcrpf = 0; | 187 | u32 srcrpf = 0; |
219 | 188 | ||
220 | if (!full) { | 189 | if (params == VSP1_ENTITY_PARAMS_RUNTIME) { |
221 | const unsigned int mask = BIT(WPF_CTRL_VFLIP) | 190 | const unsigned int mask = BIT(WPF_CTRL_VFLIP) |
222 | | BIT(WPF_CTRL_HFLIP); | 191 | | BIT(WPF_CTRL_HFLIP); |
192 | unsigned long flags; | ||
223 | 193 | ||
224 | spin_lock(&wpf->flip.lock); | 194 | spin_lock_irqsave(&wpf->flip.lock, flags); |
225 | wpf->flip.active = (wpf->flip.active & ~mask) | 195 | wpf->flip.active = (wpf->flip.active & ~mask) |
226 | | (wpf->flip.pending & mask); | 196 | | (wpf->flip.pending & mask); |
227 | spin_unlock(&wpf->flip.lock); | 197 | spin_unlock_irqrestore(&wpf->flip.lock, flags); |
228 | 198 | ||
229 | outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt; | 199 | outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt; |
230 | 200 | ||
@@ -237,17 +207,6 @@ static void wpf_configure(struct vsp1_entity *entity, | |||
237 | return; | 207 | return; |
238 | } | 208 | } |
239 | 209 | ||
240 | /* Cropping */ | ||
241 | crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config); | ||
242 | |||
243 | vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | | ||
244 | (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) | | ||
245 | (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT)); | ||
246 | vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN | | ||
247 | (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) | | ||
248 | (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT)); | ||
249 | |||
250 | /* Format */ | ||
251 | sink_format = vsp1_entity_get_pad_format(&wpf->entity, | 210 | sink_format = vsp1_entity_get_pad_format(&wpf->entity, |
252 | wpf->entity.config, | 211 | wpf->entity.config, |
253 | RWPF_PAD_SINK); | 212 | RWPF_PAD_SINK); |
@@ -255,6 +214,80 @@ static void wpf_configure(struct vsp1_entity *entity, | |||
255 | wpf->entity.config, | 214 | wpf->entity.config, |
256 | RWPF_PAD_SOURCE); | 215 | RWPF_PAD_SOURCE); |
257 | 216 | ||
217 | if (params == VSP1_ENTITY_PARAMS_PARTITION) { | ||
218 | const struct v4l2_pix_format_mplane *format = &wpf->format; | ||
219 | struct vsp1_rwpf_memory mem = wpf->mem; | ||
220 | unsigned int flip = wpf->flip.active; | ||
221 | unsigned int width = source_format->width; | ||
222 | unsigned int height = source_format->height; | ||
223 | unsigned int offset; | ||
224 | |||
225 | /* | ||
226 | * Cropping. The partition algorithm can split the image into | ||
227 | * multiple slices. | ||
228 | */ | ||
229 | if (pipe->partitions > 1) | ||
230 | width = pipe->partition.width; | ||
231 | |||
232 | vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | | ||
233 | (0 << VI6_WPF_SZCLIP_OFST_SHIFT) | | ||
234 | (width << VI6_WPF_SZCLIP_SIZE_SHIFT)); | ||
235 | vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN | | ||
236 | (0 << VI6_WPF_SZCLIP_OFST_SHIFT) | | ||
237 | (height << VI6_WPF_SZCLIP_SIZE_SHIFT)); | ||
238 | |||
239 | if (pipe->lif) | ||
240 | return; | ||
241 | |||
242 | /* | ||
243 | * Update the memory offsets based on flipping configuration. | ||
244 | * The destination addresses point to the locations where the | ||
245 | * VSP starts writing to memory, which can be different corners | ||
246 | * of the image depending on vertical flipping. | ||
247 | */ | ||
248 | if (pipe->partitions > 1) { | ||
249 | const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; | ||
250 | |||
251 | /* | ||
252 | * Horizontal flipping is handled through a line buffer | ||
253 | * and doesn't modify the start address, but still needs | ||
254 | * to be handled when image partitioning is in effect to | ||
255 | * order the partitions correctly. | ||
256 | */ | ||
257 | if (flip & BIT(WPF_CTRL_HFLIP)) | ||
258 | offset = format->width - pipe->partition.left | ||
259 | - pipe->partition.width; | ||
260 | else | ||
261 | offset = pipe->partition.left; | ||
262 | |||
263 | mem.addr[0] += offset * fmtinfo->bpp[0] / 8; | ||
264 | if (format->num_planes > 1) { | ||
265 | mem.addr[1] += offset / fmtinfo->hsub | ||
266 | * fmtinfo->bpp[1] / 8; | ||
267 | mem.addr[2] += offset / fmtinfo->hsub | ||
268 | * fmtinfo->bpp[2] / 8; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | if (flip & BIT(WPF_CTRL_VFLIP)) { | ||
273 | mem.addr[0] += (format->height - 1) | ||
274 | * format->plane_fmt[0].bytesperline; | ||
275 | |||
276 | if (format->num_planes > 1) { | ||
277 | offset = (format->height / wpf->fmtinfo->vsub - 1) | ||
278 | * format->plane_fmt[1].bytesperline; | ||
279 | mem.addr[1] += offset; | ||
280 | mem.addr[2] += offset; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]); | ||
285 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]); | ||
286 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]); | ||
287 | return; | ||
288 | } | ||
289 | |||
290 | /* Format */ | ||
258 | if (!pipe->lif) { | 291 | if (!pipe->lif) { |
259 | const struct v4l2_pix_format_mplane *format = &wpf->format; | 292 | const struct v4l2_pix_format_mplane *format = &wpf->format; |
260 | const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; | 293 | const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; |
@@ -318,12 +351,11 @@ static void wpf_configure(struct vsp1_entity *entity, | |||
318 | /* Enable interrupts */ | 351 | /* Enable interrupts */ |
319 | vsp1_dl_list_write(dl, VI6_WPF_IRQ_STA(wpf->entity.index), 0); | 352 | vsp1_dl_list_write(dl, VI6_WPF_IRQ_STA(wpf->entity.index), 0); |
320 | vsp1_dl_list_write(dl, VI6_WPF_IRQ_ENB(wpf->entity.index), | 353 | vsp1_dl_list_write(dl, VI6_WPF_IRQ_ENB(wpf->entity.index), |
321 | VI6_WFP_IRQ_ENB_FREE); | 354 | VI6_WFP_IRQ_ENB_DFEE); |
322 | } | 355 | } |
323 | 356 | ||
324 | static const struct vsp1_entity_operations wpf_entity_ops = { | 357 | static const struct vsp1_entity_operations wpf_entity_ops = { |
325 | .destroy = vsp1_wpf_destroy, | 358 | .destroy = vsp1_wpf_destroy, |
326 | .set_memory = wpf_set_memory, | ||
327 | .configure = wpf_configure, | 359 | .configure = wpf_configure, |
328 | }; | 360 | }; |
329 | 361 | ||
@@ -360,7 +392,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) | |||
360 | return ERR_PTR(ret); | 392 | return ERR_PTR(ret); |
361 | 393 | ||
362 | /* Initialize the display list manager. */ | 394 | /* Initialize the display list manager. */ |
363 | wpf->dlm = vsp1_dlm_create(vsp1, index, 4); | 395 | wpf->dlm = vsp1_dlm_create(vsp1, index, 64); |
364 | if (!wpf->dlm) { | 396 | if (!wpf->dlm) { |
365 | ret = -ENOMEM; | 397 | ret = -ENOMEM; |
366 | goto error; | 398 | goto error; |
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 7ae1a134b1ff..1d5836c3fb7a 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c | |||
@@ -474,7 +474,7 @@ static void xvip_dma_stop_streaming(struct vb2_queue *vq) | |||
474 | spin_unlock_irq(&dma->queued_lock); | 474 | spin_unlock_irq(&dma->queued_lock); |
475 | } | 475 | } |
476 | 476 | ||
477 | static struct vb2_ops xvip_dma_queue_qops = { | 477 | static const struct vb2_ops xvip_dma_queue_qops = { |
478 | .queue_setup = xvip_dma_queue_setup, | 478 | .queue_setup = xvip_dma_queue_setup, |
479 | .buf_prepare = xvip_dma_buffer_prepare, | 479 | .buf_prepare = xvip_dma_buffer_prepare, |
480 | .buf_queue = xvip_dma_buffer_queue, | 480 | .buf_queue = xvip_dma_buffer_queue, |
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 471d6a8ae8a4..ee0470a3196b 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c | |||
@@ -509,7 +509,6 @@ static SIMPLE_DEV_PM_OPS(si470x_i2c_pm, si470x_i2c_suspend, si470x_i2c_resume); | |||
509 | static struct i2c_driver si470x_i2c_driver = { | 509 | static struct i2c_driver si470x_i2c_driver = { |
510 | .driver = { | 510 | .driver = { |
511 | .name = "si470x", | 511 | .name = "si470x", |
512 | .owner = THIS_MODULE, | ||
513 | #ifdef CONFIG_PM_SLEEP | 512 | #ifdef CONFIG_PM_SLEEP |
514 | .pm = &si470x_i2c_pm, | 513 | .pm = &si470x_i2c_pm, |
515 | #endif | 514 | #endif |
diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c index 5146be2a1a50..e5e5a1672bdb 100644 --- a/drivers/media/radio/si4713/radio-usb-si4713.c +++ b/drivers/media/radio/si4713/radio-usb-si4713.c | |||
@@ -402,7 +402,7 @@ static u32 si4713_functionality(struct i2c_adapter *adapter) | |||
402 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | 402 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; |
403 | } | 403 | } |
404 | 404 | ||
405 | static struct i2c_algorithm si4713_algo = { | 405 | static const struct i2c_algorithm si4713_algo = { |
406 | .master_xfer = si4713_transfer, | 406 | .master_xfer = si4713_transfer, |
407 | .functionality = si4713_functionality, | 407 | .functionality = si4713_functionality, |
408 | }; | 408 | }; |
diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c index e0c531fa01da..5cf983be07a2 100644 --- a/drivers/media/rc/igorplugusb.c +++ b/drivers/media/rc/igorplugusb.c | |||
@@ -203,7 +203,8 @@ static int igorplugusb_probe(struct usb_interface *intf, | |||
203 | * This device can only store 36 pulses + spaces, which is not enough | 203 | * This device can only store 36 pulses + spaces, which is not enough |
204 | * for the NEC protocol and many others. | 204 | * for the NEC protocol and many others. |
205 | */ | 205 | */ |
206 | rc->allowed_protocols = RC_BIT_ALL & ~(RC_BIT_NEC | RC_BIT_RC6_6A_20 | | 206 | rc->allowed_protocols = RC_BIT_ALL & ~(RC_BIT_NEC | RC_BIT_NECX | |
207 | RC_BIT_NEC32 | RC_BIT_RC6_6A_20 | | ||
207 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | | 208 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | |
208 | RC_BIT_SONY20 | RC_BIT_MCE_KBD | RC_BIT_SANYO); | 209 | RC_BIT_SONY20 | RC_BIT_MCE_KBD | RC_BIT_SANYO); |
209 | 210 | ||
diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c index 27a7ea8f1260..09314933ea08 100644 --- a/drivers/media/rc/img-ir/img-ir-nec.c +++ b/drivers/media/rc/img-ir/img-ir-nec.c | |||
@@ -34,19 +34,21 @@ static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols, | |||
34 | bitrev8(addr_inv) << 16 | | 34 | bitrev8(addr_inv) << 16 | |
35 | bitrev8(data) << 8 | | 35 | bitrev8(data) << 8 | |
36 | bitrev8(data_inv); | 36 | bitrev8(data_inv); |
37 | request->protocol = RC_TYPE_NEC32; | ||
37 | } else if ((addr_inv ^ addr) != 0xff) { | 38 | } else if ((addr_inv ^ addr) != 0xff) { |
38 | /* Extended NEC */ | 39 | /* Extended NEC */ |
39 | /* scan encoding: AAaaDD */ | 40 | /* scan encoding: AAaaDD */ |
40 | request->scancode = addr << 16 | | 41 | request->scancode = addr << 16 | |
41 | addr_inv << 8 | | 42 | addr_inv << 8 | |
42 | data; | 43 | data; |
44 | request->protocol = RC_TYPE_NECX; | ||
43 | } else { | 45 | } else { |
44 | /* Normal NEC */ | 46 | /* Normal NEC */ |
45 | /* scan encoding: AADD */ | 47 | /* scan encoding: AADD */ |
46 | request->scancode = addr << 8 | | 48 | request->scancode = addr << 8 | |
47 | data; | 49 | data; |
50 | request->protocol = RC_TYPE_NEC; | ||
48 | } | 51 | } |
49 | request->protocol = RC_TYPE_NEC; | ||
50 | return IMG_IR_SCANCODE; | 52 | return IMG_IR_SCANCODE; |
51 | } | 53 | } |
52 | 54 | ||
@@ -109,7 +111,7 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in, | |||
109 | * http://wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol | 111 | * http://wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol |
110 | */ | 112 | */ |
111 | struct img_ir_decoder img_ir_nec = { | 113 | struct img_ir_decoder img_ir_nec = { |
112 | .type = RC_BIT_NEC, | 114 | .type = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32, |
113 | .control = { | 115 | .control = { |
114 | .decoden = 1, | 116 | .decoden = 1, |
115 | .code_type = IMG_IR_CODETYPE_PULSEDIST, | 117 | .code_type = IMG_IR_CODETYPE_PULSEDIST, |
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index bea0d1eedee0..2a9d155548ab 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c | |||
@@ -49,6 +49,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) | |||
49 | { | 49 | { |
50 | struct nec_dec *data = &dev->raw->nec; | 50 | struct nec_dec *data = &dev->raw->nec; |
51 | u32 scancode; | 51 | u32 scancode; |
52 | enum rc_type rc_type; | ||
52 | u8 address, not_address, command, not_command; | 53 | u8 address, not_address, command, not_command; |
53 | bool send_32bits = false; | 54 | bool send_32bits = false; |
54 | 55 | ||
@@ -171,22 +172,25 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) | |||
171 | * least Apple and TiVo remotes */ | 172 | * least Apple and TiVo remotes */ |
172 | scancode = data->bits; | 173 | scancode = data->bits; |
173 | IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode); | 174 | IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode); |
175 | rc_type = RC_TYPE_NEC32; | ||
174 | } else if ((address ^ not_address) != 0xff) { | 176 | } else if ((address ^ not_address) != 0xff) { |
175 | /* Extended NEC */ | 177 | /* Extended NEC */ |
176 | scancode = address << 16 | | 178 | scancode = address << 16 | |
177 | not_address << 8 | | 179 | not_address << 8 | |
178 | command; | 180 | command; |
179 | IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode); | 181 | IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode); |
182 | rc_type = RC_TYPE_NECX; | ||
180 | } else { | 183 | } else { |
181 | /* Normal NEC */ | 184 | /* Normal NEC */ |
182 | scancode = address << 8 | command; | 185 | scancode = address << 8 | command; |
183 | IR_dprintk(1, "NEC scancode 0x%04x\n", scancode); | 186 | IR_dprintk(1, "NEC scancode 0x%04x\n", scancode); |
187 | rc_type = RC_TYPE_NEC; | ||
184 | } | 188 | } |
185 | 189 | ||
186 | if (data->is_nec_x) | 190 | if (data->is_nec_x) |
187 | data->necx_repeat = true; | 191 | data->necx_repeat = true; |
188 | 192 | ||
189 | rc_keydown(dev, RC_TYPE_NEC, scancode, 0); | 193 | rc_keydown(dev, rc_type, scancode, 0); |
190 | data->state = STATE_INACTIVE; | 194 | data->state = STATE_INACTIVE; |
191 | return 0; | 195 | return 0; |
192 | } | 196 | } |
@@ -198,7 +202,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) | |||
198 | } | 202 | } |
199 | 203 | ||
200 | static struct ir_raw_handler nec_handler = { | 204 | static struct ir_raw_handler nec_handler = { |
201 | .protocols = RC_BIT_NEC, | 205 | .protocols = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32, |
202 | .decode = ir_nec_decode, | 206 | .decode = ir_nec_decode, |
203 | }; | 207 | }; |
204 | 208 | ||
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index e0e2edefa651..5cc54c967a80 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c | |||
@@ -248,7 +248,7 @@ again: | |||
248 | toggle = 0; | 248 | toggle = 0; |
249 | break; | 249 | break; |
250 | case 24: | 250 | case 24: |
251 | protocol = RC_BIT_RC6_6A_24; | 251 | protocol = RC_TYPE_RC6_6A_24; |
252 | toggle = 0; | 252 | toggle = 0; |
253 | break; | 253 | break; |
254 | case 32: | 254 | case 32: |
@@ -257,7 +257,7 @@ again: | |||
257 | toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK); | 257 | toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK); |
258 | scancode &= ~RC6_6A_MCE_TOGGLE_MASK; | 258 | scancode &= ~RC6_6A_MCE_TOGGLE_MASK; |
259 | } else { | 259 | } else { |
260 | protocol = RC_BIT_RC6_6A_32; | 260 | protocol = RC_TYPE_RC6_6A_32; |
261 | toggle = 0; | 261 | toggle = 0; |
262 | } | 262 | } |
263 | break; | 263 | break; |
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 00215f343819..04fedaa75612 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c | |||
@@ -769,21 +769,11 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt) | |||
769 | rawir.pulse ? "pulse" : "space", rawir.duration); | 769 | rawir.pulse ? "pulse" : "space", rawir.duration); |
770 | 770 | ||
771 | ir_raw_event_store_with_filter(nvt->rdev, &rawir); | 771 | ir_raw_event_store_with_filter(nvt->rdev, &rawir); |
772 | |||
773 | /* | ||
774 | * BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE | ||
775 | * indicates end of IR signal, but new data incoming. In both | ||
776 | * cases, it means we're ready to call ir_raw_event_handle | ||
777 | */ | ||
778 | if ((sample == BUF_PULSE_BIT) && (i + 1 < nvt->pkts)) { | ||
779 | nvt_dbg("Calling ir_raw_event_handle (signal end)\n"); | ||
780 | ir_raw_event_handle(nvt->rdev); | ||
781 | } | ||
782 | } | 772 | } |
783 | 773 | ||
784 | nvt->pkts = 0; | 774 | nvt->pkts = 0; |
785 | 775 | ||
786 | nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n"); | 776 | nvt_dbg("Calling ir_raw_event_handle\n"); |
787 | ir_raw_event_handle(nvt->rdev); | 777 | ir_raw_event_handle(nvt->rdev); |
788 | 778 | ||
789 | nvt_dbg_verbose("%s done", __func__); | 779 | nvt_dbg_verbose("%s done", __func__); |
@@ -801,8 +791,7 @@ static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt) | |||
801 | /* copy data from hardware rx fifo into driver buffer */ | 791 | /* copy data from hardware rx fifo into driver buffer */ |
802 | static void nvt_get_rx_ir_data(struct nvt_dev *nvt) | 792 | static void nvt_get_rx_ir_data(struct nvt_dev *nvt) |
803 | { | 793 | { |
804 | u8 fifocount, val; | 794 | u8 fifocount; |
805 | unsigned int b_idx; | ||
806 | int i; | 795 | int i; |
807 | 796 | ||
808 | /* Get count of how many bytes to read from RX FIFO */ | 797 | /* Get count of how many bytes to read from RX FIFO */ |
@@ -810,21 +799,11 @@ static void nvt_get_rx_ir_data(struct nvt_dev *nvt) | |||
810 | 799 | ||
811 | nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount); | 800 | nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount); |
812 | 801 | ||
813 | b_idx = nvt->pkts; | ||
814 | |||
815 | /* This should never happen, but lets check anyway... */ | ||
816 | if (b_idx + fifocount > RX_BUF_LEN) { | ||
817 | nvt_process_rx_ir_data(nvt); | ||
818 | b_idx = 0; | ||
819 | } | ||
820 | |||
821 | /* Read fifocount bytes from CIR Sample RX FIFO register */ | 802 | /* Read fifocount bytes from CIR Sample RX FIFO register */ |
822 | for (i = 0; i < fifocount; i++) { | 803 | for (i = 0; i < fifocount; i++) |
823 | val = nvt_cir_reg_read(nvt, CIR_SRXFIFO); | 804 | nvt->buf[i] = nvt_cir_reg_read(nvt, CIR_SRXFIFO); |
824 | nvt->buf[b_idx + i] = val; | ||
825 | } | ||
826 | 805 | ||
827 | nvt->pkts += fifocount; | 806 | nvt->pkts = fifocount; |
828 | nvt_dbg("%s: pkts now %d", __func__, nvt->pkts); | 807 | nvt_dbg("%s: pkts now %d", __func__, nvt->pkts); |
829 | 808 | ||
830 | nvt_process_rx_ir_data(nvt); | 809 | nvt_process_rx_ir_data(nvt); |
@@ -886,6 +865,15 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) | |||
886 | status = nvt_cir_reg_read(nvt, CIR_IRSTS); | 865 | status = nvt_cir_reg_read(nvt, CIR_IRSTS); |
887 | iren = nvt_cir_reg_read(nvt, CIR_IREN); | 866 | iren = nvt_cir_reg_read(nvt, CIR_IREN); |
888 | 867 | ||
868 | /* At least NCT6779D creates a spurious interrupt when the | ||
869 | * logical device is being disabled. | ||
870 | */ | ||
871 | if (status == 0xff && iren == 0xff) { | ||
872 | spin_unlock_irqrestore(&nvt->nvt_lock, flags); | ||
873 | nvt_dbg_verbose("Spurious interrupt detected"); | ||
874 | return IRQ_HANDLED; | ||
875 | } | ||
876 | |||
889 | /* IRQ may be shared with CIR WAKE, therefore check for each | 877 | /* IRQ may be shared with CIR WAKE, therefore check for each |
890 | * status bit whether the related interrupt source is enabled | 878 | * status bit whether the related interrupt source is enabled |
891 | */ | 879 | */ |
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 144304c94606..205ecc602e34 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c | |||
@@ -26,6 +26,7 @@ static LIST_HEAD(ir_raw_client_list); | |||
26 | /* Used to handle IR raw handler extensions */ | 26 | /* Used to handle IR raw handler extensions */ |
27 | static DEFINE_MUTEX(ir_raw_handler_lock); | 27 | static DEFINE_MUTEX(ir_raw_handler_lock); |
28 | static LIST_HEAD(ir_raw_handler_list); | 28 | static LIST_HEAD(ir_raw_handler_list); |
29 | static DEFINE_MUTEX(available_protocols_lock); | ||
29 | static u64 available_protocols; | 30 | static u64 available_protocols; |
30 | 31 | ||
31 | static int ir_raw_event_thread(void *data) | 32 | static int ir_raw_event_thread(void *data) |
@@ -234,9 +235,9 @@ u64 | |||
234 | ir_raw_get_allowed_protocols(void) | 235 | ir_raw_get_allowed_protocols(void) |
235 | { | 236 | { |
236 | u64 protocols; | 237 | u64 protocols; |
237 | mutex_lock(&ir_raw_handler_lock); | 238 | mutex_lock(&available_protocols_lock); |
238 | protocols = available_protocols; | 239 | protocols = available_protocols; |
239 | mutex_unlock(&ir_raw_handler_lock); | 240 | mutex_unlock(&available_protocols_lock); |
240 | return protocols; | 241 | return protocols; |
241 | } | 242 | } |
242 | 243 | ||
@@ -330,7 +331,9 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) | |||
330 | if (ir_raw_handler->raw_register) | 331 | if (ir_raw_handler->raw_register) |
331 | list_for_each_entry(raw, &ir_raw_client_list, list) | 332 | list_for_each_entry(raw, &ir_raw_client_list, list) |
332 | ir_raw_handler->raw_register(raw->dev); | 333 | ir_raw_handler->raw_register(raw->dev); |
334 | mutex_lock(&available_protocols_lock); | ||
333 | available_protocols |= ir_raw_handler->protocols; | 335 | available_protocols |= ir_raw_handler->protocols; |
336 | mutex_unlock(&available_protocols_lock); | ||
334 | mutex_unlock(&ir_raw_handler_lock); | 337 | mutex_unlock(&ir_raw_handler_lock); |
335 | 338 | ||
336 | return 0; | 339 | return 0; |
@@ -349,7 +352,9 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) | |||
349 | if (ir_raw_handler->raw_unregister) | 352 | if (ir_raw_handler->raw_unregister) |
350 | ir_raw_handler->raw_unregister(raw->dev); | 353 | ir_raw_handler->raw_unregister(raw->dev); |
351 | } | 354 | } |
355 | mutex_lock(&available_protocols_lock); | ||
352 | available_protocols &= ~protocols; | 356 | available_protocols &= ~protocols; |
357 | mutex_unlock(&available_protocols_lock); | ||
353 | mutex_unlock(&ir_raw_handler_lock); | 358 | mutex_unlock(&ir_raw_handler_lock); |
354 | } | 359 | } |
355 | EXPORT_SYMBOL(ir_raw_handler_unregister); | 360 | EXPORT_SYMBOL(ir_raw_handler_unregister); |
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 8e7f2929fa6f..d9c1f2ff7119 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c | |||
@@ -795,7 +795,9 @@ static const struct { | |||
795 | { RC_BIT_UNKNOWN, "unknown", NULL }, | 795 | { RC_BIT_UNKNOWN, "unknown", NULL }, |
796 | { RC_BIT_RC5 | | 796 | { RC_BIT_RC5 | |
797 | RC_BIT_RC5X, "rc-5", "ir-rc5-decoder" }, | 797 | RC_BIT_RC5X, "rc-5", "ir-rc5-decoder" }, |
798 | { RC_BIT_NEC, "nec", "ir-nec-decoder" }, | 798 | { RC_BIT_NEC | |
799 | RC_BIT_NECX | | ||
800 | RC_BIT_NEC32, "nec", "ir-nec-decoder" }, | ||
799 | { RC_BIT_RC6_0 | | 801 | { RC_BIT_RC6_0 | |
800 | RC_BIT_RC6_6A_20 | | 802 | RC_BIT_RC6_6A_20 | |
801 | RC_BIT_RC6_6A_24 | | 803 | RC_BIT_RC6_6A_24 | |
@@ -1460,6 +1462,10 @@ int rc_register_device(struct rc_dev *dev) | |||
1460 | dev->input_dev->phys = dev->input_phys; | 1462 | dev->input_dev->phys = dev->input_phys; |
1461 | dev->input_dev->name = dev->input_name; | 1463 | dev->input_dev->name = dev->input_name; |
1462 | 1464 | ||
1465 | rc = input_register_device(dev->input_dev); | ||
1466 | if (rc) | ||
1467 | goto out_table; | ||
1468 | |||
1463 | /* | 1469 | /* |
1464 | * Default delay of 250ms is too short for some protocols, especially | 1470 | * Default delay of 250ms is too short for some protocols, especially |
1465 | * since the timeout is currently set to 250ms. Increase it to 500ms, | 1471 | * since the timeout is currently set to 250ms. Increase it to 500ms, |
@@ -1475,11 +1481,6 @@ int rc_register_device(struct rc_dev *dev) | |||
1475 | */ | 1481 | */ |
1476 | dev->input_dev->rep[REP_PERIOD] = 125; | 1482 | dev->input_dev->rep[REP_PERIOD] = 125; |
1477 | 1483 | ||
1478 | /* rc_open will be called here */ | ||
1479 | rc = input_register_device(dev->input_dev); | ||
1480 | if (rc) | ||
1481 | goto out_table; | ||
1482 | |||
1483 | path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); | 1484 | path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); |
1484 | dev_info(&dev->dev, "%s as %s\n", | 1485 | dev_info(&dev->dev, "%s as %s\n", |
1485 | dev->input_name ?: "Unspecified device", path ?: "N/A"); | 1486 | dev->input_name ?: "Unspecified device", path ?: "N/A"); |
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index ec8016d9b009..05ba47bc0b61 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c | |||
@@ -124,6 +124,41 @@ | |||
124 | #define USB_RR3USB_PRODUCT_ID 0x0001 | 124 | #define USB_RR3USB_PRODUCT_ID 0x0001 |
125 | #define USB_RR3IIUSB_PRODUCT_ID 0x0005 | 125 | #define USB_RR3IIUSB_PRODUCT_ID 0x0005 |
126 | 126 | ||
127 | |||
128 | /* | ||
129 | * The redrat3 encodes an IR signal as set of different lengths and a set | ||
130 | * of indices into those lengths. This sets how much two lengths must | ||
131 | * differ before they are considered distinct, the value is specified | ||
132 | * in microseconds. | ||
133 | * Default 5, value 0 to 127. | ||
134 | */ | ||
135 | static int length_fuzz = 5; | ||
136 | module_param(length_fuzz, uint, 0644); | ||
137 | MODULE_PARM_DESC(length_fuzz, "Length Fuzz (0-127)"); | ||
138 | |||
139 | /* | ||
140 | * When receiving a continuous ir stream (for example when a user is | ||
141 | * holding a button down on a remote), this specifies the minimum size | ||
142 | * of a space when the redrat3 sends a irdata packet to the host. Specified | ||
143 | * in miliseconds. Default value 18ms. | ||
144 | * The value can be between 2 and 30 inclusive. | ||
145 | */ | ||
146 | static int minimum_pause = 18; | ||
147 | module_param(minimum_pause, uint, 0644); | ||
148 | MODULE_PARM_DESC(minimum_pause, "Minimum Pause in ms (2-30)"); | ||
149 | |||
150 | /* | ||
151 | * The carrier frequency is measured during the first pulse of the IR | ||
152 | * signal. The larger the number of periods used To measure, the more | ||
153 | * accurate the result is likely to be, however some signals have short | ||
154 | * initial pulses, so in some case it may be necessary to reduce this value. | ||
155 | * Default 8, value 1 to 255. | ||
156 | */ | ||
157 | static int periods_measure_carrier = 8; | ||
158 | module_param(periods_measure_carrier, uint, 0644); | ||
159 | MODULE_PARM_DESC(periods_measure_carrier, "Number of Periods to Measure Carrier (1-255)"); | ||
160 | |||
161 | |||
127 | struct redrat3_header { | 162 | struct redrat3_header { |
128 | __be16 length; | 163 | __be16 length; |
129 | __be16 transfer_type; | 164 | __be16 transfer_type; |
@@ -188,9 +223,6 @@ struct redrat3_dev { | |||
188 | /* usb dma */ | 223 | /* usb dma */ |
189 | dma_addr_t dma_in; | 224 | dma_addr_t dma_in; |
190 | 225 | ||
191 | /* rx signal timeout */ | ||
192 | u32 hw_timeout; | ||
193 | |||
194 | /* Is the device currently transmitting?*/ | 226 | /* Is the device currently transmitting?*/ |
195 | bool transmitting; | 227 | bool transmitting; |
196 | 228 | ||
@@ -372,7 +404,7 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) | |||
372 | /* add a trailing space */ | 404 | /* add a trailing space */ |
373 | rawir.pulse = false; | 405 | rawir.pulse = false; |
374 | rawir.timeout = true; | 406 | rawir.timeout = true; |
375 | rawir.duration = US_TO_NS(rr3->hw_timeout); | 407 | rawir.duration = rr3->rc->timeout; |
376 | dev_dbg(dev, "storing trailing timeout with duration %d\n", | 408 | dev_dbg(dev, "storing trailing timeout with duration %d\n", |
377 | rawir.duration); | 409 | rawir.duration); |
378 | ir_raw_event_store_with_filter(rr3->rc, &rawir); | 410 | ir_raw_event_store_with_filter(rr3->rc, &rawir); |
@@ -480,7 +512,7 @@ static int redrat3_set_timeout(struct rc_dev *rc_dev, unsigned int timeoutns) | |||
480 | struct redrat3_dev *rr3 = rc_dev->priv; | 512 | struct redrat3_dev *rr3 = rc_dev->priv; |
481 | struct usb_device *udev = rr3->udev; | 513 | struct usb_device *udev = rr3->udev; |
482 | struct device *dev = rr3->dev; | 514 | struct device *dev = rr3->dev; |
483 | u32 *timeout; | 515 | __be32 *timeout; |
484 | int ret; | 516 | int ret; |
485 | 517 | ||
486 | timeout = kmalloc(sizeof(*timeout), GFP_KERNEL); | 518 | timeout = kmalloc(sizeof(*timeout), GFP_KERNEL); |
@@ -495,10 +527,9 @@ static int redrat3_set_timeout(struct rc_dev *rc_dev, unsigned int timeoutns) | |||
495 | dev_dbg(dev, "set ir parm timeout %d ret 0x%02x\n", | 527 | dev_dbg(dev, "set ir parm timeout %d ret 0x%02x\n", |
496 | be32_to_cpu(*timeout), ret); | 528 | be32_to_cpu(*timeout), ret); |
497 | 529 | ||
498 | if (ret == sizeof(*timeout)) { | 530 | if (ret == sizeof(*timeout)) |
499 | rr3->hw_timeout = timeoutns / 1000; | ||
500 | ret = 0; | 531 | ret = 0; |
501 | } else if (ret >= 0) | 532 | else if (ret >= 0) |
502 | ret = -EIO; | 533 | ret = -EIO; |
503 | 534 | ||
504 | kfree(timeout); | 535 | kfree(timeout); |
@@ -529,12 +560,25 @@ static void redrat3_reset(struct redrat3_dev *rr3) | |||
529 | RR3_CPUCS_REG_ADDR, 0, val, len, HZ * 25); | 560 | RR3_CPUCS_REG_ADDR, 0, val, len, HZ * 25); |
530 | dev_dbg(dev, "reset returned 0x%02x\n", rc); | 561 | dev_dbg(dev, "reset returned 0x%02x\n", rc); |
531 | 562 | ||
532 | *val = 5; | 563 | *val = length_fuzz; |
533 | rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, | 564 | rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, |
534 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | 565 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, |
535 | RR3_IR_IO_LENGTH_FUZZ, 0, val, len, HZ * 25); | 566 | RR3_IR_IO_LENGTH_FUZZ, 0, val, len, HZ * 25); |
536 | dev_dbg(dev, "set ir parm len fuzz %d rc 0x%02x\n", *val, rc); | 567 | dev_dbg(dev, "set ir parm len fuzz %d rc 0x%02x\n", *val, rc); |
537 | 568 | ||
569 | *val = (65536 - (minimum_pause * 2000)) / 256; | ||
570 | rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, | ||
571 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
572 | RR3_IR_IO_MIN_PAUSE, 0, val, len, HZ * 25); | ||
573 | dev_dbg(dev, "set ir parm min pause %d rc 0x%02x\n", *val, rc); | ||
574 | |||
575 | *val = periods_measure_carrier; | ||
576 | rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, | ||
577 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
578 | RR3_IR_IO_PERIODS_MF, 0, val, len, HZ * 25); | ||
579 | dev_dbg(dev, "set ir parm periods measure carrier %d rc 0x%02x", *val, | ||
580 | rc); | ||
581 | |||
538 | *val = RR3_DRIVER_MAXLENS; | 582 | *val = RR3_DRIVER_MAXLENS; |
539 | rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, | 583 | rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, |
540 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | 584 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, |
@@ -889,7 +933,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) | |||
889 | rc->allowed_protocols = RC_BIT_ALL; | 933 | rc->allowed_protocols = RC_BIT_ALL; |
890 | rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT); | 934 | rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT); |
891 | rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT); | 935 | rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT); |
892 | rc->timeout = US_TO_NS(rr3->hw_timeout); | 936 | rc->timeout = US_TO_NS(redrat3_get_timeout(rr3)); |
893 | rc->s_timeout = redrat3_set_timeout; | 937 | rc->s_timeout = redrat3_set_timeout; |
894 | rc->tx_ir = redrat3_transmit_ir; | 938 | rc->tx_ir = redrat3_transmit_ir; |
895 | rc->s_tx_carrier = redrat3_set_tx_carrier; | 939 | rc->s_tx_carrier = redrat3_set_tx_carrier; |
@@ -998,9 +1042,6 @@ static int redrat3_dev_probe(struct usb_interface *intf, | |||
998 | if (retval < 0) | 1042 | if (retval < 0) |
999 | goto error; | 1043 | goto error; |
1000 | 1044 | ||
1001 | /* store current hardware timeout, in µs */ | ||
1002 | rr3->hw_timeout = redrat3_get_timeout(rr3); | ||
1003 | |||
1004 | /* default.. will get overridden by any sends with a freq defined */ | 1045 | /* default.. will get overridden by any sends with a freq defined */ |
1005 | rr3->carrier = 38000; | 1046 | rr3->carrier = 38000; |
1006 | 1047 | ||
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index 815243c65bc3..4004260a7c69 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c | |||
@@ -499,7 +499,7 @@ static int streamzap_resume(struct usb_interface *intf) | |||
499 | struct streamzap_ir *sz = usb_get_intfdata(intf); | 499 | struct streamzap_ir *sz = usb_get_intfdata(intf); |
500 | 500 | ||
501 | if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { | 501 | if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { |
502 | dev_err(sz->dev, "Error sumbiting urb\n"); | 502 | dev_err(sz->dev, "Error submitting urb\n"); |
503 | return -EIO; | 503 | return -EIO; |
504 | } | 504 | } |
505 | 505 | ||
diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig new file mode 100644 index 000000000000..a21f5a39a440 --- /dev/null +++ b/drivers/media/spi/Kconfig | |||
@@ -0,0 +1,14 @@ | |||
1 | if VIDEO_V4L2 | ||
2 | |||
3 | menu "SPI helper chips" | ||
4 | visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST | ||
5 | |||
6 | config VIDEO_GS1662 | ||
7 | tristate "Gennum Serializers video" | ||
8 | depends on SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
9 | ---help--- | ||
10 | Enable the GS1662 driver which serializes video streams. | ||
11 | |||
12 | endmenu | ||
13 | |||
14 | endif | ||
diff --git a/drivers/media/spi/Makefile b/drivers/media/spi/Makefile new file mode 100644 index 000000000000..ea64013d16cc --- /dev/null +++ b/drivers/media/spi/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_VIDEO_GS1662) += gs1662.o | |||
diff --git a/drivers/media/spi/gs1662.c b/drivers/media/spi/gs1662.c new file mode 100644 index 000000000000..d76f36233f43 --- /dev/null +++ b/drivers/media/spi/gs1662.c | |||
@@ -0,0 +1,478 @@ | |||
1 | /* | ||
2 | * GS1662 device registration. | ||
3 | * | ||
4 | * Copyright (C) 2015-2016 Nexvision | ||
5 | * Author: Charles-Antoine Couret <charles-antoine.couret@nexvision.fr> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/ctype.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/module.h> | ||
21 | |||
22 | #include <linux/videodev2.h> | ||
23 | #include <media/v4l2-common.h> | ||
24 | #include <media/v4l2-ctrls.h> | ||
25 | #include <media/v4l2-device.h> | ||
26 | #include <media/v4l2-subdev.h> | ||
27 | #include <media/v4l2-dv-timings.h> | ||
28 | #include <linux/v4l2-dv-timings.h> | ||
29 | |||
30 | #define REG_STATUS 0x04 | ||
31 | #define REG_FORCE_FMT 0x06 | ||
32 | #define REG_LINES_PER_FRAME 0x12 | ||
33 | #define REG_WORDS_PER_LINE 0x13 | ||
34 | #define REG_WORDS_PER_ACT_LINE 0x14 | ||
35 | #define REG_ACT_LINES_PER_FRAME 0x15 | ||
36 | |||
37 | #define MASK_H_LOCK 0x001 | ||
38 | #define MASK_V_LOCK 0x002 | ||
39 | #define MASK_STD_LOCK 0x004 | ||
40 | #define MASK_FORCE_STD 0x020 | ||
41 | #define MASK_STD_STATUS 0x3E0 | ||
42 | |||
43 | #define GS_WIDTH_MIN 720 | ||
44 | #define GS_WIDTH_MAX 2048 | ||
45 | #define GS_HEIGHT_MIN 487 | ||
46 | #define GS_HEIGHT_MAX 1080 | ||
47 | #define GS_PIXELCLOCK_MIN 10519200 | ||
48 | #define GS_PIXELCLOCK_MAX 74250000 | ||
49 | |||
50 | struct gs { | ||
51 | struct spi_device *pdev; | ||
52 | struct v4l2_subdev sd; | ||
53 | struct v4l2_dv_timings current_timings; | ||
54 | int enabled; | ||
55 | }; | ||
56 | |||
57 | struct gs_reg_fmt { | ||
58 | u16 reg_value; | ||
59 | struct v4l2_dv_timings format; | ||
60 | }; | ||
61 | |||
62 | struct gs_reg_fmt_custom { | ||
63 | u16 reg_value; | ||
64 | __u32 width; | ||
65 | __u32 height; | ||
66 | __u64 pixelclock; | ||
67 | __u32 interlaced; | ||
68 | }; | ||
69 | |||
70 | static const struct spi_device_id gs_id[] = { | ||
71 | { "gs1662", 0 }, | ||
72 | { } | ||
73 | }; | ||
74 | MODULE_DEVICE_TABLE(spi, gs_id); | ||
75 | |||
76 | static const struct v4l2_dv_timings fmt_cap[] = { | ||
77 | V4L2_DV_BT_SDI_720X487I60, | ||
78 | V4L2_DV_BT_CEA_720X576P50, | ||
79 | V4L2_DV_BT_CEA_1280X720P24, | ||
80 | V4L2_DV_BT_CEA_1280X720P25, | ||
81 | V4L2_DV_BT_CEA_1280X720P30, | ||
82 | V4L2_DV_BT_CEA_1280X720P50, | ||
83 | V4L2_DV_BT_CEA_1280X720P60, | ||
84 | V4L2_DV_BT_CEA_1920X1080P24, | ||
85 | V4L2_DV_BT_CEA_1920X1080P25, | ||
86 | V4L2_DV_BT_CEA_1920X1080P30, | ||
87 | V4L2_DV_BT_CEA_1920X1080I50, | ||
88 | V4L2_DV_BT_CEA_1920X1080I60, | ||
89 | }; | ||
90 | |||
91 | static const struct gs_reg_fmt reg_fmt[] = { | ||
92 | { 0x00, V4L2_DV_BT_CEA_1280X720P60 }, | ||
93 | { 0x01, V4L2_DV_BT_CEA_1280X720P60 }, | ||
94 | { 0x02, V4L2_DV_BT_CEA_1280X720P30 }, | ||
95 | { 0x03, V4L2_DV_BT_CEA_1280X720P30 }, | ||
96 | { 0x04, V4L2_DV_BT_CEA_1280X720P50 }, | ||
97 | { 0x05, V4L2_DV_BT_CEA_1280X720P50 }, | ||
98 | { 0x06, V4L2_DV_BT_CEA_1280X720P25 }, | ||
99 | { 0x07, V4L2_DV_BT_CEA_1280X720P25 }, | ||
100 | { 0x08, V4L2_DV_BT_CEA_1280X720P24 }, | ||
101 | { 0x09, V4L2_DV_BT_CEA_1280X720P24 }, | ||
102 | { 0x0A, V4L2_DV_BT_CEA_1920X1080I60 }, | ||
103 | { 0x0B, V4L2_DV_BT_CEA_1920X1080P30 }, | ||
104 | |||
105 | /* Default value: keep this field before 0xC */ | ||
106 | { 0x14, V4L2_DV_BT_CEA_1920X1080I50 }, | ||
107 | { 0x0C, V4L2_DV_BT_CEA_1920X1080I50 }, | ||
108 | { 0x0D, V4L2_DV_BT_CEA_1920X1080P25 }, | ||
109 | { 0x0E, V4L2_DV_BT_CEA_1920X1080P25 }, | ||
110 | { 0x10, V4L2_DV_BT_CEA_1920X1080P24 }, | ||
111 | { 0x12, V4L2_DV_BT_CEA_1920X1080P24 }, | ||
112 | { 0x16, V4L2_DV_BT_SDI_720X487I60 }, | ||
113 | { 0x19, V4L2_DV_BT_SDI_720X487I60 }, | ||
114 | { 0x18, V4L2_DV_BT_CEA_720X576P50 }, | ||
115 | { 0x1A, V4L2_DV_BT_CEA_720X576P50 }, | ||
116 | |||
117 | /* Implement following timings before enable it. | ||
118 | * Because of we don't have access to these theoretical timings yet. | ||
119 | * Workaround: use functions to get and set registers for these formats. | ||
120 | */ | ||
121 | #if 0 | ||
122 | { 0x0F, V4L2_DV_BT_XXX_1920X1080I25 }, /* SMPTE 274M */ | ||
123 | { 0x11, V4L2_DV_BT_XXX_1920X1080I24 }, /* SMPTE 274M */ | ||
124 | { 0x13, V4L2_DV_BT_XXX_1920X1080I25 }, /* SMPTE 274M */ | ||
125 | { 0x15, V4L2_DV_BT_XXX_1920X1035I60 }, /* SMPTE 260M */ | ||
126 | { 0x17, V4L2_DV_BT_SDI_720X507I60 }, /* SMPTE 125M */ | ||
127 | { 0x1B, V4L2_DV_BT_SDI_720X507I60 }, /* SMPTE 125M */ | ||
128 | { 0x1C, V4L2_DV_BT_XXX_2048X1080P25 }, /* SMPTE 428.1M */ | ||
129 | #endif | ||
130 | }; | ||
131 | |||
132 | static const struct v4l2_dv_timings_cap gs_timings_cap = { | ||
133 | .type = V4L2_DV_BT_656_1120, | ||
134 | /* keep this initialization for compatibility with GCC < 4.4.6 */ | ||
135 | .reserved = { 0 }, | ||
136 | V4L2_INIT_BT_TIMINGS(GS_WIDTH_MIN, GS_WIDTH_MAX, GS_HEIGHT_MIN, | ||
137 | GS_HEIGHT_MAX, GS_PIXELCLOCK_MIN, | ||
138 | GS_PIXELCLOCK_MAX, | ||
139 | V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_SDI, | ||
140 | V4L2_DV_BT_CAP_PROGRESSIVE | ||
141 | | V4L2_DV_BT_CAP_INTERLACED) | ||
142 | }; | ||
143 | |||
144 | static int gs_read_register(struct spi_device *spi, u16 addr, u16 *value) | ||
145 | { | ||
146 | int ret; | ||
147 | u16 buf_addr = (0x8000 | (0x0FFF & addr)); | ||
148 | u16 buf_value = 0; | ||
149 | struct spi_message msg; | ||
150 | struct spi_transfer tx[] = { | ||
151 | { | ||
152 | .tx_buf = &buf_addr, | ||
153 | .len = 2, | ||
154 | .delay_usecs = 1, | ||
155 | }, { | ||
156 | .rx_buf = &buf_value, | ||
157 | .len = 2, | ||
158 | .delay_usecs = 1, | ||
159 | }, | ||
160 | }; | ||
161 | |||
162 | spi_message_init(&msg); | ||
163 | spi_message_add_tail(&tx[0], &msg); | ||
164 | spi_message_add_tail(&tx[1], &msg); | ||
165 | ret = spi_sync(spi, &msg); | ||
166 | |||
167 | *value = buf_value; | ||
168 | |||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static int gs_write_register(struct spi_device *spi, u16 addr, u16 value) | ||
173 | { | ||
174 | int ret; | ||
175 | u16 buf_addr = addr; | ||
176 | u16 buf_value = value; | ||
177 | struct spi_message msg; | ||
178 | struct spi_transfer tx[] = { | ||
179 | { | ||
180 | .tx_buf = &buf_addr, | ||
181 | .len = 2, | ||
182 | .delay_usecs = 1, | ||
183 | }, { | ||
184 | .tx_buf = &buf_value, | ||
185 | .len = 2, | ||
186 | .delay_usecs = 1, | ||
187 | }, | ||
188 | }; | ||
189 | |||
190 | spi_message_init(&msg); | ||
191 | spi_message_add_tail(&tx[0], &msg); | ||
192 | spi_message_add_tail(&tx[1], &msg); | ||
193 | ret = spi_sync(spi, &msg); | ||
194 | |||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
199 | static int gs_g_register(struct v4l2_subdev *sd, | ||
200 | struct v4l2_dbg_register *reg) | ||
201 | { | ||
202 | struct spi_device *spi = v4l2_get_subdevdata(sd); | ||
203 | u16 val; | ||
204 | int ret; | ||
205 | |||
206 | ret = gs_read_register(spi, reg->reg & 0xFFFF, &val); | ||
207 | reg->val = val; | ||
208 | reg->size = 2; | ||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | static int gs_s_register(struct v4l2_subdev *sd, | ||
213 | const struct v4l2_dbg_register *reg) | ||
214 | { | ||
215 | struct spi_device *spi = v4l2_get_subdevdata(sd); | ||
216 | |||
217 | return gs_write_register(spi, reg->reg & 0xFFFF, reg->val & 0xFFFF); | ||
218 | } | ||
219 | #endif | ||
220 | |||
221 | static int gs_status_format(u16 status, struct v4l2_dv_timings *timings) | ||
222 | { | ||
223 | int std = (status & MASK_STD_STATUS) >> 5; | ||
224 | int i; | ||
225 | |||
226 | for (i = 0; i < ARRAY_SIZE(reg_fmt); i++) { | ||
227 | if (reg_fmt[i].reg_value == std) { | ||
228 | *timings = reg_fmt[i].format; | ||
229 | return 0; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | return -ERANGE; | ||
234 | } | ||
235 | |||
236 | static u16 get_register_timings(struct v4l2_dv_timings *timings) | ||
237 | { | ||
238 | int i; | ||
239 | |||
240 | for (i = 0; i < ARRAY_SIZE(reg_fmt); i++) { | ||
241 | if (v4l2_match_dv_timings(timings, ®_fmt[i].format, 0, | ||
242 | false)) | ||
243 | return reg_fmt[i].reg_value | MASK_FORCE_STD; | ||
244 | } | ||
245 | |||
246 | return 0x0; | ||
247 | } | ||
248 | |||
249 | static inline struct gs *to_gs(struct v4l2_subdev *sd) | ||
250 | { | ||
251 | return container_of(sd, struct gs, sd); | ||
252 | } | ||
253 | |||
254 | static int gs_s_dv_timings(struct v4l2_subdev *sd, | ||
255 | struct v4l2_dv_timings *timings) | ||
256 | { | ||
257 | struct gs *gs = to_gs(sd); | ||
258 | int reg_value; | ||
259 | |||
260 | reg_value = get_register_timings(timings); | ||
261 | if (reg_value == 0x0) | ||
262 | return -EINVAL; | ||
263 | |||
264 | gs->current_timings = *timings; | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static int gs_g_dv_timings(struct v4l2_subdev *sd, | ||
269 | struct v4l2_dv_timings *timings) | ||
270 | { | ||
271 | struct gs *gs = to_gs(sd); | ||
272 | |||
273 | *timings = gs->current_timings; | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static int gs_query_dv_timings(struct v4l2_subdev *sd, | ||
278 | struct v4l2_dv_timings *timings) | ||
279 | { | ||
280 | struct gs *gs = to_gs(sd); | ||
281 | struct v4l2_dv_timings fmt; | ||
282 | u16 reg_value, i; | ||
283 | int ret; | ||
284 | |||
285 | if (gs->enabled) | ||
286 | return -EBUSY; | ||
287 | |||
288 | /* | ||
289 | * Check if the component detect a line, a frame or something else | ||
290 | * which looks like a video signal activity. | ||
291 | */ | ||
292 | for (i = 0; i < 4; i++) { | ||
293 | gs_read_register(gs->pdev, REG_LINES_PER_FRAME + i, ®_value); | ||
294 | if (reg_value) | ||
295 | break; | ||
296 | } | ||
297 | |||
298 | /* If no register reports a video signal */ | ||
299 | if (i >= 4) | ||
300 | return -ENOLINK; | ||
301 | |||
302 | gs_read_register(gs->pdev, REG_STATUS, ®_value); | ||
303 | if (!(reg_value & MASK_H_LOCK) || !(reg_value & MASK_V_LOCK)) | ||
304 | return -ENOLCK; | ||
305 | if (!(reg_value & MASK_STD_LOCK)) | ||
306 | return -ERANGE; | ||
307 | |||
308 | ret = gs_status_format(reg_value, &fmt); | ||
309 | |||
310 | if (ret < 0) | ||
311 | return ret; | ||
312 | |||
313 | *timings = fmt; | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static int gs_enum_dv_timings(struct v4l2_subdev *sd, | ||
318 | struct v4l2_enum_dv_timings *timings) | ||
319 | { | ||
320 | if (timings->index >= ARRAY_SIZE(fmt_cap)) | ||
321 | return -EINVAL; | ||
322 | |||
323 | if (timings->pad != 0) | ||
324 | return -EINVAL; | ||
325 | |||
326 | timings->timings = fmt_cap[timings->index]; | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int gs_s_stream(struct v4l2_subdev *sd, int enable) | ||
331 | { | ||
332 | struct gs *gs = to_gs(sd); | ||
333 | int reg_value; | ||
334 | |||
335 | if (gs->enabled == enable) | ||
336 | return 0; | ||
337 | |||
338 | gs->enabled = enable; | ||
339 | |||
340 | if (enable) { | ||
341 | /* To force the specific format */ | ||
342 | reg_value = get_register_timings(&gs->current_timings); | ||
343 | return gs_write_register(gs->pdev, REG_FORCE_FMT, reg_value); | ||
344 | } | ||
345 | |||
346 | /* To renable auto-detection mode */ | ||
347 | return gs_write_register(gs->pdev, REG_FORCE_FMT, 0x0); | ||
348 | } | ||
349 | |||
350 | static int gs_g_input_status(struct v4l2_subdev *sd, u32 *status) | ||
351 | { | ||
352 | struct gs *gs = to_gs(sd); | ||
353 | u16 reg_value, i; | ||
354 | int ret; | ||
355 | |||
356 | /* | ||
357 | * Check if the component detect a line, a frame or something else | ||
358 | * which looks like a video signal activity. | ||
359 | */ | ||
360 | for (i = 0; i < 4; i++) { | ||
361 | ret = gs_read_register(gs->pdev, | ||
362 | REG_LINES_PER_FRAME + i, ®_value); | ||
363 | if (reg_value) | ||
364 | break; | ||
365 | if (ret) { | ||
366 | *status = V4L2_IN_ST_NO_POWER; | ||
367 | return ret; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | /* If no register reports a video signal */ | ||
372 | if (i >= 4) | ||
373 | *status |= V4L2_IN_ST_NO_SIGNAL; | ||
374 | |||
375 | ret = gs_read_register(gs->pdev, REG_STATUS, ®_value); | ||
376 | if (!(reg_value & MASK_H_LOCK)) | ||
377 | *status |= V4L2_IN_ST_NO_H_LOCK; | ||
378 | if (!(reg_value & MASK_V_LOCK)) | ||
379 | *status |= V4L2_IN_ST_NO_V_LOCK; | ||
380 | if (!(reg_value & MASK_STD_LOCK)) | ||
381 | *status |= V4L2_IN_ST_NO_STD_LOCK; | ||
382 | |||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | static int gs_dv_timings_cap(struct v4l2_subdev *sd, | ||
387 | struct v4l2_dv_timings_cap *cap) | ||
388 | { | ||
389 | if (cap->pad != 0) | ||
390 | return -EINVAL; | ||
391 | |||
392 | *cap = gs_timings_cap; | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | /* V4L2 core operation handlers */ | ||
397 | static const struct v4l2_subdev_core_ops gs_core_ops = { | ||
398 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
399 | .g_register = gs_g_register, | ||
400 | .s_register = gs_s_register, | ||
401 | #endif | ||
402 | }; | ||
403 | |||
404 | static const struct v4l2_subdev_video_ops gs_video_ops = { | ||
405 | .s_dv_timings = gs_s_dv_timings, | ||
406 | .g_dv_timings = gs_g_dv_timings, | ||
407 | .s_stream = gs_s_stream, | ||
408 | .g_input_status = gs_g_input_status, | ||
409 | .query_dv_timings = gs_query_dv_timings, | ||
410 | }; | ||
411 | |||
412 | static const struct v4l2_subdev_pad_ops gs_pad_ops = { | ||
413 | .enum_dv_timings = gs_enum_dv_timings, | ||
414 | .dv_timings_cap = gs_dv_timings_cap, | ||
415 | }; | ||
416 | |||
417 | /* V4L2 top level operation handlers */ | ||
418 | static const struct v4l2_subdev_ops gs_ops = { | ||
419 | .core = &gs_core_ops, | ||
420 | .video = &gs_video_ops, | ||
421 | .pad = &gs_pad_ops, | ||
422 | }; | ||
423 | |||
424 | static int gs_probe(struct spi_device *spi) | ||
425 | { | ||
426 | int ret; | ||
427 | struct gs *gs; | ||
428 | struct v4l2_subdev *sd; | ||
429 | |||
430 | gs = devm_kzalloc(&spi->dev, sizeof(struct gs), GFP_KERNEL); | ||
431 | if (!gs) | ||
432 | return -ENOMEM; | ||
433 | |||
434 | gs->pdev = spi; | ||
435 | sd = &gs->sd; | ||
436 | |||
437 | spi->mode = SPI_MODE_0; | ||
438 | spi->irq = -1; | ||
439 | spi->max_speed_hz = 10000000; | ||
440 | spi->bits_per_word = 16; | ||
441 | ret = spi_setup(spi); | ||
442 | v4l2_spi_subdev_init(sd, spi, &gs_ops); | ||
443 | |||
444 | gs->current_timings = reg_fmt[0].format; | ||
445 | gs->enabled = 0; | ||
446 | |||
447 | /* Set H_CONFIG to SMPTE timings */ | ||
448 | gs_write_register(spi, 0x0, 0x300); | ||
449 | |||
450 | return ret; | ||
451 | } | ||
452 | |||
453 | static int gs_remove(struct spi_device *spi) | ||
454 | { | ||
455 | struct v4l2_subdev *sd = spi_get_drvdata(spi); | ||
456 | struct gs *gs = to_gs(sd); | ||
457 | |||
458 | v4l2_device_unregister_subdev(sd); | ||
459 | kfree(gs); | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static struct spi_driver gs_driver = { | ||
464 | .driver = { | ||
465 | .name = "gs1662", | ||
466 | .owner = THIS_MODULE, | ||
467 | }, | ||
468 | |||
469 | .probe = gs_probe, | ||
470 | .remove = gs_remove, | ||
471 | .id_table = gs_id, | ||
472 | }; | ||
473 | |||
474 | module_spi_driver(gs_driver); | ||
475 | |||
476 | MODULE_LICENSE("GPL"); | ||
477 | MODULE_AUTHOR("Charles-Antoine Couret <charles-antoine.couret@nexvision.fr>"); | ||
478 | MODULE_DESCRIPTION("Gennum GS1662 HD/SD-SDI Serializer driver"); | ||
diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index 7f0b9d5940db..dfec23743afe 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c | |||
@@ -2201,7 +2201,7 @@ static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw) | |||
2201 | return 0; | 2201 | return 0; |
2202 | } | 2202 | } |
2203 | 2203 | ||
2204 | static struct dvb_tuner_ops mt2063_ops = { | 2204 | static const struct dvb_tuner_ops mt2063_ops = { |
2205 | .info = { | 2205 | .info = { |
2206 | .name = "MT2063 Silicon Tuner", | 2206 | .name = "MT2063 Silicon Tuner", |
2207 | .frequency_min = 45000000, | 2207 | .frequency_min = 45000000, |
diff --git a/drivers/media/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c index 9e031040c13f..52da4671b0e0 100644 --- a/drivers/media/tuners/mt20xx.c +++ b/drivers/media/tuners/mt20xx.c | |||
@@ -363,7 +363,7 @@ static int mt2032_set_params(struct dvb_frontend *fe, | |||
363 | return ret; | 363 | return ret; |
364 | } | 364 | } |
365 | 365 | ||
366 | static struct dvb_tuner_ops mt2032_tuner_ops = { | 366 | static const struct dvb_tuner_ops mt2032_tuner_ops = { |
367 | .set_analog_params = mt2032_set_params, | 367 | .set_analog_params = mt2032_set_params, |
368 | .release = microtune_release, | 368 | .release = microtune_release, |
369 | .get_frequency = microtune_get_frequency, | 369 | .get_frequency = microtune_get_frequency, |
@@ -563,7 +563,7 @@ static int mt2050_set_params(struct dvb_frontend *fe, | |||
563 | return ret; | 563 | return ret; |
564 | } | 564 | } |
565 | 565 | ||
566 | static struct dvb_tuner_ops mt2050_tuner_ops = { | 566 | static const struct dvb_tuner_ops mt2050_tuner_ops = { |
567 | .set_analog_params = mt2050_set_params, | 567 | .set_analog_params = mt2050_set_params, |
568 | .release = microtune_release, | 568 | .release = microtune_release, |
569 | .get_frequency = microtune_get_frequency, | 569 | .get_frequency = microtune_get_frequency, |
diff --git a/drivers/media/tuners/mxl5007t.c b/drivers/media/tuners/mxl5007t.c index f4ae04c3328a..42569c6811e6 100644 --- a/drivers/media/tuners/mxl5007t.c +++ b/drivers/media/tuners/mxl5007t.c | |||
@@ -794,7 +794,7 @@ static int mxl5007t_release(struct dvb_frontend *fe) | |||
794 | 794 | ||
795 | /* ------------------------------------------------------------------------- */ | 795 | /* ------------------------------------------------------------------------- */ |
796 | 796 | ||
797 | static struct dvb_tuner_ops mxl5007t_tuner_ops = { | 797 | static const struct dvb_tuner_ops mxl5007t_tuner_ops = { |
798 | .info = { | 798 | .info = { |
799 | .name = "MaxLinear MxL5007T", | 799 | .name = "MaxLinear MxL5007T", |
800 | }, | 800 | }, |
diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c index f8620741bb5f..2d50e8b1dce1 100644 --- a/drivers/media/tuners/tda18271-fe.c +++ b/drivers/media/tuners/tda18271-fe.c | |||
@@ -18,11 +18,12 @@ | |||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/videodev2.h> | ||
23 | #include "tda18271-priv.h" | 21 | #include "tda18271-priv.h" |
24 | #include "tda8290.h" | 22 | #include "tda8290.h" |
25 | 23 | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/videodev2.h> | ||
26 | |||
26 | int tda18271_debug; | 27 | int tda18271_debug; |
27 | module_param_named(debug, tda18271_debug, int, 0644); | 28 | module_param_named(debug, tda18271_debug, int, 0644); |
28 | MODULE_PARM_DESC(debug, "set debug level " | 29 | MODULE_PARM_DESC(debug, "set debug level " |
@@ -646,7 +647,7 @@ static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe) | |||
646 | unsigned int i; | 647 | unsigned int i; |
647 | int ret; | 648 | int ret; |
648 | 649 | ||
649 | tda_info("tda18271: performing RF tracking filter calibration\n"); | 650 | tda_info("performing RF tracking filter calibration\n"); |
650 | 651 | ||
651 | /* wait for die temperature stabilization */ | 652 | /* wait for die temperature stabilization */ |
652 | msleep(200); | 653 | msleep(200); |
@@ -692,12 +693,12 @@ static int tda18271c2_rf_cal_init(struct dvb_frontend *fe) | |||
692 | if (tda_fail(ret)) | 693 | if (tda_fail(ret)) |
693 | goto fail; | 694 | goto fail; |
694 | 695 | ||
695 | tda_info("tda18271: RF tracking filter calibration complete\n"); | 696 | tda_info("RF tracking filter calibration complete\n"); |
696 | 697 | ||
697 | priv->cal_initialized = true; | 698 | priv->cal_initialized = true; |
698 | goto end; | 699 | goto end; |
699 | fail: | 700 | fail: |
700 | tda_info("tda18271: RF tracking filter calibration failed!\n"); | 701 | tda_info("RF tracking filter calibration failed!\n"); |
701 | end: | 702 | end: |
702 | return ret; | 703 | return ret; |
703 | } | 704 | } |
diff --git a/drivers/media/tuners/tda18271-priv.h b/drivers/media/tuners/tda18271-priv.h index cc80f544af34..0bcc735a0427 100644 --- a/drivers/media/tuners/tda18271-priv.h +++ b/drivers/media/tuners/tda18271-priv.h | |||
@@ -21,6 +21,8 @@ | |||
21 | #ifndef __TDA18271_PRIV_H__ | 21 | #ifndef __TDA18271_PRIV_H__ |
22 | #define __TDA18271_PRIV_H__ | 22 | #define __TDA18271_PRIV_H__ |
23 | 23 | ||
24 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
25 | |||
24 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
25 | #include <linux/types.h> | 27 | #include <linux/types.h> |
26 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
diff --git a/drivers/media/tuners/tda827x.c b/drivers/media/tuners/tda827x.c index edcb4a723aa1..5050ce9be423 100644 --- a/drivers/media/tuners/tda827x.c +++ b/drivers/media/tuners/tda827x.c | |||
@@ -818,7 +818,7 @@ static int tda827x_initial_sleep(struct dvb_frontend *fe) | |||
818 | return fe->ops.tuner_ops.sleep(fe); | 818 | return fe->ops.tuner_ops.sleep(fe); |
819 | } | 819 | } |
820 | 820 | ||
821 | static struct dvb_tuner_ops tda827xo_tuner_ops = { | 821 | static const struct dvb_tuner_ops tda827xo_tuner_ops = { |
822 | .info = { | 822 | .info = { |
823 | .name = "Philips TDA827X", | 823 | .name = "Philips TDA827X", |
824 | .frequency_min = 55000000, | 824 | .frequency_min = 55000000, |
@@ -834,7 +834,7 @@ static struct dvb_tuner_ops tda827xo_tuner_ops = { | |||
834 | .get_bandwidth = tda827x_get_bandwidth, | 834 | .get_bandwidth = tda827x_get_bandwidth, |
835 | }; | 835 | }; |
836 | 836 | ||
837 | static struct dvb_tuner_ops tda827xa_tuner_ops = { | 837 | static const struct dvb_tuner_ops tda827xa_tuner_ops = { |
838 | .info = { | 838 | .info = { |
839 | .name = "Philips TDA827XA", | 839 | .name = "Philips TDA827XA", |
840 | .frequency_min = 44000000, | 840 | .frequency_min = 44000000, |
diff --git a/drivers/media/tuners/tea5761.c b/drivers/media/tuners/tea5761.c index bf78cb9fc52c..36b0b1e1d05b 100644 --- a/drivers/media/tuners/tea5761.c +++ b/drivers/media/tuners/tea5761.c | |||
@@ -301,7 +301,7 @@ static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) | |||
301 | return 0; | 301 | return 0; |
302 | } | 302 | } |
303 | 303 | ||
304 | static struct dvb_tuner_ops tea5761_tuner_ops = { | 304 | static const struct dvb_tuner_ops tea5761_tuner_ops = { |
305 | .info = { | 305 | .info = { |
306 | .name = "tea5761", // Philips TEA5761HN FM Radio | 306 | .name = "tea5761", // Philips TEA5761HN FM Radio |
307 | }, | 307 | }, |
diff --git a/drivers/media/tuners/tea5767.c b/drivers/media/tuners/tea5767.c index 36e85d81acb2..d62a6d6b1f42 100644 --- a/drivers/media/tuners/tea5767.c +++ b/drivers/media/tuners/tea5767.c | |||
@@ -10,6 +10,8 @@ | |||
10 | * from their contributions on DScaler. | 10 | * from their contributions on DScaler. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
14 | |||
13 | #include <linux/i2c.h> | 15 | #include <linux/i2c.h> |
14 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
15 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
@@ -370,17 +372,18 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) | |||
370 | { | 372 | { |
371 | struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; | 373 | struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; |
372 | unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | 374 | unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
375 | |||
373 | int rc; | 376 | int rc; |
374 | 377 | ||
375 | if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) { | 378 | if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) { |
376 | printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc); | 379 | pr_warn("It is not a TEA5767. Received %i bytes.\n", rc); |
377 | return -EINVAL; | 380 | return -EINVAL; |
378 | } | 381 | } |
379 | 382 | ||
380 | /* If all bytes are the same then it's a TV tuner and not a tea5767 */ | 383 | /* If all bytes are the same then it's a TV tuner and not a tea5767 */ |
381 | if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && | 384 | if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && |
382 | buffer[0] == buffer[3] && buffer[0] == buffer[4]) { | 385 | buffer[0] == buffer[3] && buffer[0] == buffer[4]) { |
383 | printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n"); | 386 | pr_warn("All bytes are equal. It is not a TEA5767\n"); |
384 | return -EINVAL; | 387 | return -EINVAL; |
385 | } | 388 | } |
386 | 389 | ||
@@ -390,7 +393,7 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) | |||
390 | * Byte 5: bit 7:0 : == 0 | 393 | * Byte 5: bit 7:0 : == 0 |
391 | */ | 394 | */ |
392 | if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { | 395 | if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { |
393 | printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n"); | 396 | pr_warn("Chip ID is not zero. It is not a TEA5767\n"); |
394 | return -EINVAL; | 397 | return -EINVAL; |
395 | } | 398 | } |
396 | 399 | ||
@@ -423,7 +426,7 @@ static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg) | |||
423 | return 0; | 426 | return 0; |
424 | } | 427 | } |
425 | 428 | ||
426 | static struct dvb_tuner_ops tea5767_tuner_ops = { | 429 | static const struct dvb_tuner_ops tea5767_tuner_ops = { |
427 | .info = { | 430 | .info = { |
428 | .name = "tea5767", // Philips TEA5767HN FM Radio | 431 | .name = "tea5767", // Philips TEA5767HN FM Radio |
429 | }, | 432 | }, |
diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c index 8e9ce144da9a..9ba9582e7765 100644 --- a/drivers/media/tuners/tuner-simple.c +++ b/drivers/media/tuners/tuner-simple.c | |||
@@ -1035,7 +1035,7 @@ static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | |||
1035 | return 0; | 1035 | return 0; |
1036 | } | 1036 | } |
1037 | 1037 | ||
1038 | static struct dvb_tuner_ops simple_tuner_ops = { | 1038 | static const struct dvb_tuner_ops simple_tuner_ops = { |
1039 | .init = simple_init, | 1039 | .init = simple_init, |
1040 | .sleep = simple_sleep, | 1040 | .sleep = simple_sleep, |
1041 | .set_analog_params = simple_set_params, | 1041 | .set_analog_params = simple_set_params, |
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 3c556ee306cd..8251942bcd12 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c | |||
@@ -605,7 +605,7 @@ static void airspy_stop_streaming(struct vb2_queue *vq) | |||
605 | mutex_unlock(&s->v4l2_lock); | 605 | mutex_unlock(&s->v4l2_lock); |
606 | } | 606 | } |
607 | 607 | ||
608 | static struct vb2_ops airspy_vb2_ops = { | 608 | static const struct vb2_ops airspy_vb2_ops = { |
609 | .queue_setup = airspy_queue_setup, | 609 | .queue_setup = airspy_queue_setup, |
610 | .buf_queue = airspy_buf_queue, | 610 | .buf_queue = airspy_buf_queue, |
611 | .start_streaming = airspy_start_streaming, | 611 | .start_streaming = airspy_start_streaming, |
diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 3d6687f0407d..1e66e7828d8f 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c | |||
@@ -344,7 +344,8 @@ int au0828_rc_register(struct au0828_dev *dev) | |||
344 | rc->dev.parent = &dev->usbdev->dev; | 344 | rc->dev.parent = &dev->usbdev->dev; |
345 | rc->driver_name = "au0828-input"; | 345 | rc->driver_name = "au0828-input"; |
346 | rc->driver_type = RC_DRIVER_IR_RAW; | 346 | rc->driver_type = RC_DRIVER_IR_RAW; |
347 | rc->allowed_protocols = RC_BIT_NEC | RC_BIT_RC5; | 347 | rc->allowed_protocols = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 | |
348 | RC_BIT_RC5; | ||
348 | 349 | ||
349 | /* all done */ | 350 | /* all done */ |
350 | err = rc_register_device(rc); | 351 | err = rc_register_device(rc); |
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 13b8387082f2..85dd9a8e83ff 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c | |||
@@ -928,7 +928,7 @@ void au0828_stop_vbi_streaming(struct vb2_queue *vq) | |||
928 | del_timer_sync(&dev->vbi_timeout); | 928 | del_timer_sync(&dev->vbi_timeout); |
929 | } | 929 | } |
930 | 930 | ||
931 | static struct vb2_ops au0828_video_qops = { | 931 | static const struct vb2_ops au0828_video_qops = { |
932 | .queue_setup = queue_setup, | 932 | .queue_setup = queue_setup, |
933 | .buf_prepare = buffer_prepare, | 933 | .buf_prepare = buffer_prepare, |
934 | .buf_queue = buffer_queue, | 934 | .buf_queue = buffer_queue, |
diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index 4cd5fa91612f..8263c4b0610b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c | |||
@@ -635,7 +635,7 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, | |||
635 | return vmalloc_to_page(pageptr); | 635 | return vmalloc_to_page(pageptr); |
636 | } | 636 | } |
637 | 637 | ||
638 | static struct snd_pcm_ops snd_cx231xx_pcm_capture = { | 638 | static const struct snd_pcm_ops snd_cx231xx_pcm_capture = { |
639 | .open = snd_cx231xx_capture_open, | 639 | .open = snd_cx231xx_capture_open, |
640 | .close = snd_cx231xx_pcm_close, | 640 | .close = snd_cx231xx_pcm_close, |
641 | .ioctl = snd_pcm_lib_ioctl, | 641 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 491913778bcc..2f52d66b4dae 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c | |||
@@ -1264,7 +1264,10 @@ int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev, | |||
1264 | dev->board.agc_analog_digital_select_gpio, | 1264 | dev->board.agc_analog_digital_select_gpio, |
1265 | analog_or_digital); | 1265 | analog_or_digital); |
1266 | 1266 | ||
1267 | return status; | 1267 | if (status < 0) |
1268 | return status; | ||
1269 | |||
1270 | return 0; | ||
1268 | } | 1271 | } |
1269 | 1272 | ||
1270 | int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3) | 1273 | int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3) |
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index c63248a18823..36bc25494319 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c | |||
@@ -486,7 +486,7 @@ struct cx231xx_board cx231xx_boards[] = { | |||
486 | .output_mode = OUT_MODE_VIP11, | 486 | .output_mode = OUT_MODE_VIP11, |
487 | .demod_xfer_mode = 0, | 487 | .demod_xfer_mode = 0, |
488 | .ctl_pin_status_mask = 0xFFFFFFC4, | 488 | .ctl_pin_status_mask = 0xFFFFFFC4, |
489 | .agc_analog_digital_select_gpio = 0x00, /* According with PV cxPolaris.inf file */ | 489 | .agc_analog_digital_select_gpio = 0x1c, |
490 | .tuner_sif_gpio = -1, | 490 | .tuner_sif_gpio = -1, |
491 | .tuner_scl_gpio = -1, | 491 | .tuner_scl_gpio = -1, |
492 | .tuner_sda_gpio = -1, | 492 | .tuner_sda_gpio = -1, |
@@ -1186,12 +1186,12 @@ static void cx231xx_unregister_media_device(struct cx231xx *dev) | |||
1186 | */ | 1186 | */ |
1187 | void cx231xx_release_resources(struct cx231xx *dev) | 1187 | void cx231xx_release_resources(struct cx231xx *dev) |
1188 | { | 1188 | { |
1189 | cx231xx_ir_exit(dev); | ||
1190 | |||
1189 | cx231xx_release_analog_resources(dev); | 1191 | cx231xx_release_analog_resources(dev); |
1190 | 1192 | ||
1191 | cx231xx_remove_from_devlist(dev); | 1193 | cx231xx_remove_from_devlist(dev); |
1192 | 1194 | ||
1193 | cx231xx_ir_exit(dev); | ||
1194 | |||
1195 | /* Release I2C buses */ | 1195 | /* Release I2C buses */ |
1196 | cx231xx_dev_uninit(dev); | 1196 | cx231xx_dev_uninit(dev); |
1197 | 1197 | ||
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 8ec05cb306d8..8b099fe1d592 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c | |||
@@ -712,6 +712,7 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode) | |||
712 | break; | 712 | break; |
713 | case CX231XX_BOARD_CNXT_RDE_253S: | 713 | case CX231XX_BOARD_CNXT_RDE_253S: |
714 | case CX231XX_BOARD_CNXT_RDU_253S: | 714 | case CX231XX_BOARD_CNXT_RDU_253S: |
715 | case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: | ||
715 | errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1); | 716 | errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1); |
716 | break; | 717 | break; |
717 | case CX231XX_BOARD_HAUPPAUGE_EXETER: | 718 | case CX231XX_BOARD_HAUPPAUGE_EXETER: |
@@ -738,14 +739,21 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode) | |||
738 | case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: | 739 | case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: |
739 | case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: | 740 | case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: |
740 | case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: | 741 | case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: |
741 | errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0); | 742 | errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0); |
742 | break; | 743 | break; |
743 | default: | 744 | default: |
744 | break; | 745 | break; |
745 | } | 746 | } |
746 | } | 747 | } |
747 | 748 | ||
748 | return errCode ? -EINVAL : 0; | 749 | if (errCode < 0) { |
750 | dev_err(dev->dev, "Failed to set devmode to %s: error: %i", | ||
751 | dev->mode == CX231XX_DIGITAL_MODE ? "digital" : "analog", | ||
752 | errCode); | ||
753 | return errCode; | ||
754 | } | ||
755 | |||
756 | return 0; | ||
749 | } | 757 | } |
750 | EXPORT_SYMBOL_GPL(cx231xx_set_mode); | 758 | EXPORT_SYMBOL_GPL(cx231xx_set_mode); |
751 | 759 | ||
@@ -799,7 +807,7 @@ static void cx231xx_isoc_irq_callback(struct urb *urb) | |||
799 | case -ESHUTDOWN: | 807 | case -ESHUTDOWN: |
800 | return; | 808 | return; |
801 | default: /* error */ | 809 | default: /* error */ |
802 | cx231xx_isocdbg("urb completition error %d.\n", urb->status); | 810 | cx231xx_isocdbg("urb completion error %d.\n", urb->status); |
803 | break; | 811 | break; |
804 | } | 812 | } |
805 | 813 | ||
@@ -842,8 +850,11 @@ static void cx231xx_bulk_irq_callback(struct urb *urb) | |||
842 | case -ENOENT: | 850 | case -ENOENT: |
843 | case -ESHUTDOWN: | 851 | case -ESHUTDOWN: |
844 | return; | 852 | return; |
853 | case -EPIPE: /* stall */ | ||
854 | cx231xx_isocdbg("urb completion error - device is stalled.\n"); | ||
855 | return; | ||
845 | default: /* error */ | 856 | default: /* error */ |
846 | cx231xx_isocdbg("urb completition error %d.\n", urb->status); | 857 | cx231xx_isocdbg("urb completion error %d.\n", urb->status); |
847 | break; | 858 | break; |
848 | } | 859 | } |
849 | 860 | ||
@@ -867,6 +878,7 @@ void cx231xx_uninit_isoc(struct cx231xx *dev) | |||
867 | struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq; | 878 | struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq; |
868 | struct urb *urb; | 879 | struct urb *urb; |
869 | int i; | 880 | int i; |
881 | bool broken_pipe = false; | ||
870 | 882 | ||
871 | cx231xx_isocdbg("cx231xx: called cx231xx_uninit_isoc\n"); | 883 | cx231xx_isocdbg("cx231xx: called cx231xx_uninit_isoc\n"); |
872 | 884 | ||
@@ -886,12 +898,19 @@ void cx231xx_uninit_isoc(struct cx231xx *dev) | |||
886 | transfer_buffer[i], | 898 | transfer_buffer[i], |
887 | urb->transfer_dma); | 899 | urb->transfer_dma); |
888 | } | 900 | } |
901 | if (urb->status == -EPIPE) { | ||
902 | broken_pipe = true; | ||
903 | } | ||
889 | usb_free_urb(urb); | 904 | usb_free_urb(urb); |
890 | dev->video_mode.isoc_ctl.urb[i] = NULL; | 905 | dev->video_mode.isoc_ctl.urb[i] = NULL; |
891 | } | 906 | } |
892 | dev->video_mode.isoc_ctl.transfer_buffer[i] = NULL; | 907 | dev->video_mode.isoc_ctl.transfer_buffer[i] = NULL; |
893 | } | 908 | } |
894 | 909 | ||
910 | if (broken_pipe) { | ||
911 | cx231xx_isocdbg("Reset endpoint to recover broken pipe."); | ||
912 | usb_reset_endpoint(dev->udev, dev->video_mode.end_point_addr); | ||
913 | } | ||
895 | kfree(dev->video_mode.isoc_ctl.urb); | 914 | kfree(dev->video_mode.isoc_ctl.urb); |
896 | kfree(dev->video_mode.isoc_ctl.transfer_buffer); | 915 | kfree(dev->video_mode.isoc_ctl.transfer_buffer); |
897 | kfree(dma_q->p_left_data); | 916 | kfree(dma_q->p_left_data); |
@@ -918,6 +937,7 @@ void cx231xx_uninit_bulk(struct cx231xx *dev) | |||
918 | struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq; | 937 | struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq; |
919 | struct urb *urb; | 938 | struct urb *urb; |
920 | int i; | 939 | int i; |
940 | bool broken_pipe = false; | ||
921 | 941 | ||
922 | cx231xx_isocdbg("cx231xx: called cx231xx_uninit_bulk\n"); | 942 | cx231xx_isocdbg("cx231xx: called cx231xx_uninit_bulk\n"); |
923 | 943 | ||
@@ -937,12 +957,19 @@ void cx231xx_uninit_bulk(struct cx231xx *dev) | |||
937 | transfer_buffer[i], | 957 | transfer_buffer[i], |
938 | urb->transfer_dma); | 958 | urb->transfer_dma); |
939 | } | 959 | } |
960 | if (urb->status == -EPIPE) { | ||
961 | broken_pipe = true; | ||
962 | } | ||
940 | usb_free_urb(urb); | 963 | usb_free_urb(urb); |
941 | dev->video_mode.bulk_ctl.urb[i] = NULL; | 964 | dev->video_mode.bulk_ctl.urb[i] = NULL; |
942 | } | 965 | } |
943 | dev->video_mode.bulk_ctl.transfer_buffer[i] = NULL; | 966 | dev->video_mode.bulk_ctl.transfer_buffer[i] = NULL; |
944 | } | 967 | } |
945 | 968 | ||
969 | if (broken_pipe) { | ||
970 | cx231xx_isocdbg("Reset endpoint to recover broken pipe."); | ||
971 | usb_reset_endpoint(dev->udev, dev->video_mode.end_point_addr); | ||
972 | } | ||
946 | kfree(dev->video_mode.bulk_ctl.urb); | 973 | kfree(dev->video_mode.bulk_ctl.urb); |
947 | kfree(dev->video_mode.bulk_ctl.transfer_buffer); | 974 | kfree(dev->video_mode.bulk_ctl.transfer_buffer); |
948 | kfree(dma_q->p_left_data); | 975 | kfree(dma_q->p_left_data); |
@@ -1297,15 +1324,29 @@ int cx231xx_dev_init(struct cx231xx *dev) | |||
1297 | dev->i2c_bus[2].i2c_reserve = 0; | 1324 | dev->i2c_bus[2].i2c_reserve = 0; |
1298 | 1325 | ||
1299 | /* register I2C buses */ | 1326 | /* register I2C buses */ |
1300 | cx231xx_i2c_register(&dev->i2c_bus[0]); | 1327 | errCode = cx231xx_i2c_register(&dev->i2c_bus[0]); |
1301 | cx231xx_i2c_register(&dev->i2c_bus[1]); | 1328 | if (errCode < 0) |
1302 | cx231xx_i2c_register(&dev->i2c_bus[2]); | 1329 | return errCode; |
1330 | errCode = cx231xx_i2c_register(&dev->i2c_bus[1]); | ||
1331 | if (errCode < 0) | ||
1332 | return errCode; | ||
1333 | errCode = cx231xx_i2c_register(&dev->i2c_bus[2]); | ||
1334 | if (errCode < 0) | ||
1335 | return errCode; | ||
1303 | 1336 | ||
1304 | errCode = cx231xx_i2c_mux_create(dev); | 1337 | errCode = cx231xx_i2c_mux_create(dev); |
1338 | if (errCode < 0) { | ||
1339 | dev_err(dev->dev, | ||
1340 | "%s: Failed to create I2C mux\n", __func__); | ||
1341 | return errCode; | ||
1342 | } | ||
1343 | errCode = cx231xx_i2c_mux_register(dev, 0); | ||
1344 | if (errCode < 0) | ||
1345 | return errCode; | ||
1346 | |||
1347 | errCode = cx231xx_i2c_mux_register(dev, 1); | ||
1305 | if (errCode < 0) | 1348 | if (errCode < 0) |
1306 | return errCode; | 1349 | return errCode; |
1307 | cx231xx_i2c_mux_register(dev, 0); | ||
1308 | cx231xx_i2c_mux_register(dev, 1); | ||
1309 | 1350 | ||
1310 | /* scan the real bus segments in the order of physical port numbers */ | 1351 | /* scan the real bus segments in the order of physical port numbers */ |
1311 | cx231xx_do_i2c_scan(dev, I2C_0); | 1352 | cx231xx_do_i2c_scan(dev, I2C_0); |
@@ -1448,14 +1489,14 @@ int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val, | |||
1448 | /* set request */ | 1489 | /* set request */ |
1449 | if (!request) { | 1490 | if (!request) { |
1450 | if (direction) | 1491 | if (direction) |
1451 | ven_req.bRequest = VRT_GET_GPIO; /* 0x8 gpio */ | 1492 | ven_req.bRequest = VRT_GET_GPIO; /* 0x9 gpio */ |
1452 | else | 1493 | else |
1453 | ven_req.bRequest = VRT_SET_GPIO; /* 0x9 gpio */ | 1494 | ven_req.bRequest = VRT_SET_GPIO; /* 0x8 gpio */ |
1454 | } else { | 1495 | } else { |
1455 | if (direction) | 1496 | if (direction) |
1456 | ven_req.bRequest = VRT_GET_GPIE; /* 0xa gpie */ | 1497 | ven_req.bRequest = VRT_GET_GPIE; /* 0xb gpie */ |
1457 | else | 1498 | else |
1458 | ven_req.bRequest = VRT_SET_GPIE; /* 0xb gpie */ | 1499 | ven_req.bRequest = VRT_SET_GPIE; /* 0xa gpie */ |
1459 | } | 1500 | } |
1460 | 1501 | ||
1461 | /* set index value */ | 1502 | /* set index value */ |
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index ab2fb9fa0cd1..1417515d30eb 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c | |||
@@ -65,6 +65,7 @@ struct cx231xx_dvb { | |||
65 | struct dmx_frontend fe_hw; | 65 | struct dmx_frontend fe_hw; |
66 | struct dmx_frontend fe_mem; | 66 | struct dmx_frontend fe_mem; |
67 | struct dvb_net net; | 67 | struct dvb_net net; |
68 | struct i2c_client *i2c_client_demod; | ||
68 | struct i2c_client *i2c_client_tuner; | 69 | struct i2c_client *i2c_client_tuner; |
69 | }; | 70 | }; |
70 | 71 | ||
@@ -150,18 +151,6 @@ static struct tda18271_config pv_tda18271_config = { | |||
150 | .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, | 151 | .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, |
151 | }; | 152 | }; |
152 | 153 | ||
153 | static const struct si2165_config hauppauge_930C_HD_1113xx_si2165_config = { | ||
154 | .i2c_addr = 0x64, | ||
155 | .chip_mode = SI2165_MODE_PLL_XTAL, | ||
156 | .ref_freq_Hz = 16000000, | ||
157 | }; | ||
158 | |||
159 | static const struct si2165_config pctv_quatro_stick_1114xx_si2165_config = { | ||
160 | .i2c_addr = 0x64, | ||
161 | .chip_mode = SI2165_MODE_PLL_EXT, | ||
162 | .ref_freq_Hz = 24000000, | ||
163 | }; | ||
164 | |||
165 | static struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = { | 154 | static struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = { |
166 | .i2c_addr = 0x59, | 155 | .i2c_addr = 0x59, |
167 | .qam_if_khz = 4000, | 156 | .qam_if_khz = 4000, |
@@ -586,8 +575,14 @@ static void unregister_dvb(struct cx231xx_dvb *dvb) | |||
586 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); | 575 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); |
587 | dvb_dmxdev_release(&dvb->dmxdev); | 576 | dvb_dmxdev_release(&dvb->dmxdev); |
588 | dvb_dmx_release(&dvb->demux); | 577 | dvb_dmx_release(&dvb->demux); |
589 | client = dvb->i2c_client_tuner; | ||
590 | /* remove I2C tuner */ | 578 | /* remove I2C tuner */ |
579 | client = dvb->i2c_client_tuner; | ||
580 | if (client) { | ||
581 | module_put(client->dev.driver->owner); | ||
582 | i2c_unregister_device(client); | ||
583 | } | ||
584 | /* remove I2C demod */ | ||
585 | client = dvb->i2c_client_demod; | ||
591 | if (client) { | 586 | if (client) { |
592 | module_put(client->dev.driver->owner); | 587 | module_put(client->dev.driver->owner); |
593 | i2c_unregister_device(client); | 588 | i2c_unregister_device(client); |
@@ -749,19 +744,38 @@ static int dvb_init(struct cx231xx *dev) | |||
749 | break; | 744 | break; |
750 | 745 | ||
751 | case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx: | 746 | case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx: |
747 | { | ||
748 | struct i2c_client *client; | ||
749 | struct i2c_board_info info; | ||
750 | struct si2165_platform_data si2165_pdata; | ||
752 | 751 | ||
753 | dev->dvb->frontend = dvb_attach(si2165_attach, | 752 | /* attach demod */ |
754 | &hauppauge_930C_HD_1113xx_si2165_config, | 753 | memset(&si2165_pdata, 0, sizeof(si2165_pdata)); |
755 | demod_i2c | 754 | si2165_pdata.fe = &dev->dvb->frontend; |
756 | ); | 755 | si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL, |
756 | si2165_pdata.ref_freq_Hz = 16000000, | ||
757 | 757 | ||
758 | if (dev->dvb->frontend == NULL) { | 758 | memset(&info, 0, sizeof(struct i2c_board_info)); |
759 | strlcpy(info.type, "si2165", I2C_NAME_SIZE); | ||
760 | info.addr = 0x64; | ||
761 | info.platform_data = &si2165_pdata; | ||
762 | request_module(info.type); | ||
763 | client = i2c_new_device(demod_i2c, &info); | ||
764 | if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) { | ||
759 | dev_err(dev->dev, | 765 | dev_err(dev->dev, |
760 | "Failed to attach SI2165 front end\n"); | 766 | "Failed to attach SI2165 front end\n"); |
761 | result = -EINVAL; | 767 | result = -EINVAL; |
762 | goto out_free; | 768 | goto out_free; |
763 | } | 769 | } |
764 | 770 | ||
771 | if (!try_module_get(client->dev.driver->owner)) { | ||
772 | i2c_unregister_device(client); | ||
773 | result = -ENODEV; | ||
774 | goto out_free; | ||
775 | } | ||
776 | |||
777 | dvb->i2c_client_demod = client; | ||
778 | |||
765 | dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; | 779 | dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; |
766 | 780 | ||
767 | /* define general-purpose callback pointer */ | 781 | /* define general-purpose callback pointer */ |
@@ -774,27 +788,43 @@ static int dvb_init(struct cx231xx *dev) | |||
774 | 788 | ||
775 | dev->cx231xx_reset_analog_tuner = NULL; | 789 | dev->cx231xx_reset_analog_tuner = NULL; |
776 | break; | 790 | break; |
777 | 791 | } | |
778 | case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: | 792 | case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: |
779 | { | 793 | { |
780 | struct i2c_client *client; | 794 | struct i2c_client *client; |
781 | struct i2c_board_info info; | 795 | struct i2c_board_info info; |
796 | struct si2165_platform_data si2165_pdata; | ||
782 | struct si2157_config si2157_config; | 797 | struct si2157_config si2157_config; |
783 | 798 | ||
784 | memset(&info, 0, sizeof(struct i2c_board_info)); | 799 | /* attach demod */ |
800 | memset(&si2165_pdata, 0, sizeof(si2165_pdata)); | ||
801 | si2165_pdata.fe = &dev->dvb->frontend; | ||
802 | si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT, | ||
803 | si2165_pdata.ref_freq_Hz = 24000000, | ||
785 | 804 | ||
786 | dev->dvb->frontend = dvb_attach(si2165_attach, | 805 | memset(&info, 0, sizeof(struct i2c_board_info)); |
787 | &pctv_quatro_stick_1114xx_si2165_config, | 806 | strlcpy(info.type, "si2165", I2C_NAME_SIZE); |
788 | demod_i2c | 807 | info.addr = 0x64; |
789 | ); | 808 | info.platform_data = &si2165_pdata; |
790 | 809 | request_module(info.type); | |
791 | if (dev->dvb->frontend == NULL) { | 810 | client = i2c_new_device(demod_i2c, &info); |
811 | if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) { | ||
792 | dev_err(dev->dev, | 812 | dev_err(dev->dev, |
793 | "Failed to attach SI2165 front end\n"); | 813 | "Failed to attach SI2165 front end\n"); |
794 | result = -EINVAL; | 814 | result = -EINVAL; |
795 | goto out_free; | 815 | goto out_free; |
796 | } | 816 | } |
797 | 817 | ||
818 | if (!try_module_get(client->dev.driver->owner)) { | ||
819 | i2c_unregister_device(client); | ||
820 | result = -ENODEV; | ||
821 | goto out_free; | ||
822 | } | ||
823 | |||
824 | dvb->i2c_client_demod = client; | ||
825 | |||
826 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
827 | |||
798 | dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; | 828 | dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; |
799 | 829 | ||
800 | /* define general-purpose callback pointer */ | 830 | /* define general-purpose callback pointer */ |
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c index 473cd3433fe5..35e9acfe63d3 100644 --- a/drivers/media/usb/cx231xx/cx231xx-i2c.c +++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c | |||
@@ -454,7 +454,7 @@ static u32 functionality(struct i2c_adapter *adap) | |||
454 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; | 454 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; |
455 | } | 455 | } |
456 | 456 | ||
457 | static struct i2c_algorithm cx231xx_algo = { | 457 | static const struct i2c_algorithm cx231xx_algo = { |
458 | .master_xfer = cx231xx_i2c_xfer, | 458 | .master_xfer = cx231xx_i2c_xfer, |
459 | .functionality = functionality, | 459 | .functionality = functionality, |
460 | }; | 460 | }; |
@@ -608,7 +608,7 @@ struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port) | |||
608 | case I2C_1_MUX_3: | 608 | case I2C_1_MUX_3: |
609 | return dev->muxc->adapter[1]; | 609 | return dev->muxc->adapter[1]; |
610 | default: | 610 | default: |
611 | return NULL; | 611 | BUG(); |
612 | } | 612 | } |
613 | } | 613 | } |
614 | EXPORT_SYMBOL_GPL(cx231xx_get_i2c_adap); | 614 | EXPORT_SYMBOL_GPL(cx231xx_get_i2c_adap); |
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 09e0f58f6bb7..941ceff9b268 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c | |||
@@ -1222,6 +1222,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) | |||
1222 | 1222 | ||
1223 | /* Only process key if canary killed */ | 1223 | /* Only process key if canary killed */ |
1224 | if (buf[16] != 0xff && buf[0] != 0x01) { | 1224 | if (buf[16] != 0xff && buf[0] != 0x01) { |
1225 | enum rc_type proto; | ||
1225 | dev_dbg(&d->udev->dev, "%s: key pressed %*ph\n", | 1226 | dev_dbg(&d->udev->dev, "%s: key pressed %*ph\n", |
1226 | __func__, 4, buf + 12); | 1227 | __func__, 4, buf + 12); |
1227 | 1228 | ||
@@ -1237,11 +1238,13 @@ static int af9015_rc_query(struct dvb_usb_device *d) | |||
1237 | /* NEC */ | 1238 | /* NEC */ |
1238 | state->rc_keycode = RC_SCANCODE_NEC(buf[12], | 1239 | state->rc_keycode = RC_SCANCODE_NEC(buf[12], |
1239 | buf[14]); | 1240 | buf[14]); |
1241 | proto = RC_TYPE_NEC; | ||
1240 | } else { | 1242 | } else { |
1241 | /* NEC extended*/ | 1243 | /* NEC extended*/ |
1242 | state->rc_keycode = RC_SCANCODE_NECX(buf[12] << 8 | | 1244 | state->rc_keycode = RC_SCANCODE_NECX(buf[12] << 8 | |
1243 | buf[13], | 1245 | buf[13], |
1244 | buf[14]); | 1246 | buf[14]); |
1247 | proto = RC_TYPE_NECX; | ||
1245 | } | 1248 | } |
1246 | } else { | 1249 | } else { |
1247 | /* 32 bit NEC */ | 1250 | /* 32 bit NEC */ |
@@ -1249,8 +1252,9 @@ static int af9015_rc_query(struct dvb_usb_device *d) | |||
1249 | buf[13] << 16 | | 1252 | buf[13] << 16 | |
1250 | buf[14] << 8 | | 1253 | buf[14] << 8 | |
1251 | buf[15]); | 1254 | buf[15]); |
1255 | proto = RC_TYPE_NEC32; | ||
1252 | } | 1256 | } |
1253 | rc_keydown(d->rc_dev, RC_TYPE_NEC, state->rc_keycode, 0); | 1257 | rc_keydown(d->rc_dev, proto, state->rc_keycode, 0); |
1254 | } else { | 1258 | } else { |
1255 | dev_dbg(&d->udev->dev, "%s: no key press\n", __func__); | 1259 | dev_dbg(&d->udev->dev, "%s: no key press\n", __func__); |
1256 | /* Invalidate last keypress */ | 1260 | /* Invalidate last keypress */ |
@@ -1317,7 +1321,7 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) | |||
1317 | if (!rc->map_name) | 1321 | if (!rc->map_name) |
1318 | rc->map_name = RC_MAP_EMPTY; | 1322 | rc->map_name = RC_MAP_EMPTY; |
1319 | 1323 | ||
1320 | rc->allowed_protos = RC_BIT_NEC; | 1324 | rc->allowed_protos = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32; |
1321 | rc->query = af9015_rc_query; | 1325 | rc->query = af9015_rc_query; |
1322 | rc->interval = 500; | 1326 | rc->interval = 500; |
1323 | 1327 | ||
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index ca018cd3fcd4..8961dd732522 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c | |||
@@ -1828,6 +1828,7 @@ static int af9035_rc_query(struct dvb_usb_device *d) | |||
1828 | { | 1828 | { |
1829 | struct usb_interface *intf = d->intf; | 1829 | struct usb_interface *intf = d->intf; |
1830 | int ret; | 1830 | int ret; |
1831 | enum rc_type proto; | ||
1831 | u32 key; | 1832 | u32 key; |
1832 | u8 buf[4]; | 1833 | u8 buf[4]; |
1833 | struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, buf }; | 1834 | struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, buf }; |
@@ -1842,19 +1843,22 @@ static int af9035_rc_query(struct dvb_usb_device *d) | |||
1842 | if ((buf[0] + buf[1]) == 0xff) { | 1843 | if ((buf[0] + buf[1]) == 0xff) { |
1843 | /* NEC standard 16bit */ | 1844 | /* NEC standard 16bit */ |
1844 | key = RC_SCANCODE_NEC(buf[0], buf[2]); | 1845 | key = RC_SCANCODE_NEC(buf[0], buf[2]); |
1846 | proto = RC_TYPE_NEC; | ||
1845 | } else { | 1847 | } else { |
1846 | /* NEC extended 24bit */ | 1848 | /* NEC extended 24bit */ |
1847 | key = RC_SCANCODE_NECX(buf[0] << 8 | buf[1], buf[2]); | 1849 | key = RC_SCANCODE_NECX(buf[0] << 8 | buf[1], buf[2]); |
1850 | proto = RC_TYPE_NECX; | ||
1848 | } | 1851 | } |
1849 | } else { | 1852 | } else { |
1850 | /* NEC full code 32bit */ | 1853 | /* NEC full code 32bit */ |
1851 | key = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 | | 1854 | key = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 | |
1852 | buf[2] << 8 | buf[3]); | 1855 | buf[2] << 8 | buf[3]); |
1856 | proto = RC_TYPE_NEC32; | ||
1853 | } | 1857 | } |
1854 | 1858 | ||
1855 | dev_dbg(&intf->dev, "%*ph\n", 4, buf); | 1859 | dev_dbg(&intf->dev, "%*ph\n", 4, buf); |
1856 | 1860 | ||
1857 | rc_keydown(d->rc_dev, RC_TYPE_NEC, key, 0); | 1861 | rc_keydown(d->rc_dev, proto, key, 0); |
1858 | 1862 | ||
1859 | return 0; | 1863 | return 0; |
1860 | 1864 | ||
@@ -1889,7 +1893,8 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) | |||
1889 | switch (tmp) { | 1893 | switch (tmp) { |
1890 | case 0: /* NEC */ | 1894 | case 0: /* NEC */ |
1891 | default: | 1895 | default: |
1892 | rc->allowed_protos = RC_BIT_NEC; | 1896 | rc->allowed_protos = RC_BIT_NEC | RC_BIT_NECX | |
1897 | RC_BIT_NEC32; | ||
1893 | break; | 1898 | break; |
1894 | case 1: /* RC6 */ | 1899 | case 1: /* RC6 */ |
1895 | rc->allowed_protos = RC_BIT_RC6_MCE; | 1900 | rc->allowed_protos = RC_BIT_RC6_MCE; |
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c index 935dbaa80ef0..50c07fe7dacb 100644 --- a/drivers/media/usb/dvb-usb-v2/az6007.c +++ b/drivers/media/usb/dvb-usb-v2/az6007.c | |||
@@ -208,6 +208,7 @@ static int az6007_rc_query(struct dvb_usb_device *d) | |||
208 | { | 208 | { |
209 | struct az6007_device_state *st = d_to_priv(d); | 209 | struct az6007_device_state *st = d_to_priv(d); |
210 | unsigned code; | 210 | unsigned code; |
211 | enum rc_type proto; | ||
211 | 212 | ||
212 | az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10); | 213 | az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10); |
213 | 214 | ||
@@ -215,19 +216,23 @@ static int az6007_rc_query(struct dvb_usb_device *d) | |||
215 | return 0; | 216 | return 0; |
216 | 217 | ||
217 | if ((st->data[3] ^ st->data[4]) == 0xff) { | 218 | if ((st->data[3] ^ st->data[4]) == 0xff) { |
218 | if ((st->data[1] ^ st->data[2]) == 0xff) | 219 | if ((st->data[1] ^ st->data[2]) == 0xff) { |
219 | code = RC_SCANCODE_NEC(st->data[1], st->data[3]); | 220 | code = RC_SCANCODE_NEC(st->data[1], st->data[3]); |
220 | else | 221 | proto = RC_TYPE_NEC; |
222 | } else { | ||
221 | code = RC_SCANCODE_NECX(st->data[1] << 8 | st->data[2], | 223 | code = RC_SCANCODE_NECX(st->data[1] << 8 | st->data[2], |
222 | st->data[3]); | 224 | st->data[3]); |
225 | proto = RC_TYPE_NECX; | ||
226 | } | ||
223 | } else { | 227 | } else { |
224 | code = RC_SCANCODE_NEC32(st->data[1] << 24 | | 228 | code = RC_SCANCODE_NEC32(st->data[1] << 24 | |
225 | st->data[2] << 16 | | 229 | st->data[2] << 16 | |
226 | st->data[3] << 8 | | 230 | st->data[3] << 8 | |
227 | st->data[4]); | 231 | st->data[4]); |
232 | proto = RC_TYPE_NEC32; | ||
228 | } | 233 | } |
229 | 234 | ||
230 | rc_keydown(d->rc_dev, RC_TYPE_NEC, code, st->data[5]); | 235 | rc_keydown(d->rc_dev, proto, code, st->data[5]); |
231 | 236 | ||
232 | return 0; | 237 | return 0; |
233 | } | 238 | } |
@@ -236,7 +241,7 @@ static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) | |||
236 | { | 241 | { |
237 | pr_debug("Getting az6007 Remote Control properties\n"); | 242 | pr_debug("Getting az6007 Remote Control properties\n"); |
238 | 243 | ||
239 | rc->allowed_protos = RC_BIT_NEC; | 244 | rc->allowed_protos = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32; |
240 | rc->query = az6007_rc_query; | 245 | rc->query = az6007_rc_query; |
241 | rc->interval = 400; | 246 | rc->interval = 400; |
242 | 247 | ||
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 3fbb2cd19f5e..a8e6624fbe83 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | |||
@@ -82,8 +82,6 @@ static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) | |||
82 | ret = i2c_add_adapter(&d->i2c_adap); | 82 | ret = i2c_add_adapter(&d->i2c_adap); |
83 | if (ret < 0) { | 83 | if (ret < 0) { |
84 | d->i2c_adap.algo = NULL; | 84 | d->i2c_adap.algo = NULL; |
85 | dev_err(&d->udev->dev, "%s: i2c_add_adapter() failed=%d\n", | ||
86 | KBUILD_MODNAME, ret); | ||
87 | goto err; | 85 | goto err; |
88 | } | 86 | } |
89 | 87 | ||
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 3721ee63b8fb..0e8fb89896c4 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c | |||
@@ -357,7 +357,8 @@ static void lme2510_int_response(struct urb *lme_urb) | |||
357 | ibuf[5]); | 357 | ibuf[5]); |
358 | 358 | ||
359 | deb_info(1, "INT Key = 0x%08x", key); | 359 | deb_info(1, "INT Key = 0x%08x", key); |
360 | rc_keydown(adap_to_d(adap)->rc_dev, RC_TYPE_NEC, key, 0); | 360 | rc_keydown(adap_to_d(adap)->rc_dev, RC_TYPE_NEC32, key, |
361 | 0); | ||
361 | break; | 362 | break; |
362 | case 0xbb: | 363 | case 0xbb: |
363 | switch (st->tuner_config) { | 364 | switch (st->tuner_config) { |
@@ -1242,7 +1243,7 @@ static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, | |||
1242 | static int lme2510_get_rc_config(struct dvb_usb_device *d, | 1243 | static int lme2510_get_rc_config(struct dvb_usb_device *d, |
1243 | struct dvb_usb_rc *rc) | 1244 | struct dvb_usb_rc *rc) |
1244 | { | 1245 | { |
1245 | rc->allowed_protos = RC_BIT_NEC; | 1246 | rc->allowed_protos = RC_BIT_NEC32; |
1246 | return 0; | 1247 | return 0; |
1247 | } | 1248 | } |
1248 | 1249 | ||
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c index 7d16252dbb71..f141dcc55cc9 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c | |||
@@ -466,7 +466,7 @@ static int mxl111sf_tuner_release(struct dvb_frontend *fe) | |||
466 | 466 | ||
467 | /* ------------------------------------------------------------------------- */ | 467 | /* ------------------------------------------------------------------------- */ |
468 | 468 | ||
469 | static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = { | 469 | static const struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = { |
470 | .info = { | 470 | .info = { |
471 | .name = "MaxLinear MxL111SF", | 471 | .name = "MaxLinear MxL111SF", |
472 | #if 0 | 472 | #if 0 |
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 6643762a9ff7..c583c638e468 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c | |||
@@ -1631,22 +1631,27 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d) | |||
1631 | goto err; | 1631 | goto err; |
1632 | 1632 | ||
1633 | if (buf[4] & 0x01) { | 1633 | if (buf[4] & 0x01) { |
1634 | enum rc_type proto; | ||
1635 | |||
1634 | if (buf[2] == (u8) ~buf[3]) { | 1636 | if (buf[2] == (u8) ~buf[3]) { |
1635 | if (buf[0] == (u8) ~buf[1]) { | 1637 | if (buf[0] == (u8) ~buf[1]) { |
1636 | /* NEC standard (16 bit) */ | 1638 | /* NEC standard (16 bit) */ |
1637 | rc_code = RC_SCANCODE_NEC(buf[0], buf[2]); | 1639 | rc_code = RC_SCANCODE_NEC(buf[0], buf[2]); |
1640 | proto = RC_TYPE_NEC; | ||
1638 | } else { | 1641 | } else { |
1639 | /* NEC extended (24 bit) */ | 1642 | /* NEC extended (24 bit) */ |
1640 | rc_code = RC_SCANCODE_NECX(buf[0] << 8 | buf[1], | 1643 | rc_code = RC_SCANCODE_NECX(buf[0] << 8 | buf[1], |
1641 | buf[2]); | 1644 | buf[2]); |
1645 | proto = RC_TYPE_NECX; | ||
1642 | } | 1646 | } |
1643 | } else { | 1647 | } else { |
1644 | /* NEC full (32 bit) */ | 1648 | /* NEC full (32 bit) */ |
1645 | rc_code = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 | | 1649 | rc_code = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 | |
1646 | buf[2] << 8 | buf[3]); | 1650 | buf[2] << 8 | buf[3]); |
1651 | proto = RC_TYPE_NEC32; | ||
1647 | } | 1652 | } |
1648 | 1653 | ||
1649 | rc_keydown(d->rc_dev, RC_TYPE_NEC, rc_code, 0); | 1654 | rc_keydown(d->rc_dev, proto, rc_code, 0); |
1650 | 1655 | ||
1651 | ret = rtl28xxu_wr_reg(d, SYS_IRRC_SR, 1); | 1656 | ret = rtl28xxu_wr_reg(d, SYS_IRRC_SR, 1); |
1652 | if (ret) | 1657 | if (ret) |
@@ -1668,7 +1673,7 @@ static int rtl2831u_get_rc_config(struct dvb_usb_device *d, | |||
1668 | struct dvb_usb_rc *rc) | 1673 | struct dvb_usb_rc *rc) |
1669 | { | 1674 | { |
1670 | rc->map_name = RC_MAP_EMPTY; | 1675 | rc->map_name = RC_MAP_EMPTY; |
1671 | rc->allowed_protos = RC_BIT_NEC; | 1676 | rc->allowed_protos = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32; |
1672 | rc->query = rtl2831u_rc_query; | 1677 | rc->query = rtl2831u_rc_query; |
1673 | rc->interval = 400; | 1678 | rc->interval = 400; |
1674 | 1679 | ||
diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig index f03b0b70c901..959fa09dfd92 100644 --- a/drivers/media/usb/dvb-usb/Kconfig +++ b/drivers/media/usb/dvb-usb/Kconfig | |||
@@ -20,10 +20,20 @@ config DVB_USB_DEBUG | |||
20 | Say Y if you want to enable debugging. See modinfo dvb-usb (and the | 20 | Say Y if you want to enable debugging. See modinfo dvb-usb (and the |
21 | appropriate drivers) for debug levels. | 21 | appropriate drivers) for debug levels. |
22 | 22 | ||
23 | config DVB_USB_DIB3000MC | ||
24 | tristate | ||
25 | depends on DVB_USB | ||
26 | select DVB_DIB3000MC | ||
27 | help | ||
28 | This is a module with helper functions for accessing the | ||
29 | DIB3000MC from USB DVB devices. It must be a separate module | ||
30 | in case DVB_USB is built-in and DVB_DIB3000MC is a module, | ||
31 | and gets selected automatically when needed. | ||
32 | |||
23 | config DVB_USB_A800 | 33 | config DVB_USB_A800 |
24 | tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" | 34 | tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" |
25 | depends on DVB_USB | 35 | depends on DVB_USB |
26 | select DVB_DIB3000MC | 36 | select DVB_USB_DIB3000MC |
27 | select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT | 37 | select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT |
28 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT | 38 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT |
29 | help | 39 | help |
@@ -34,6 +44,7 @@ config DVB_USB_DIBUSB_MB | |||
34 | depends on DVB_USB | 44 | depends on DVB_USB |
35 | select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT | 45 | select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT |
36 | select DVB_DIB3000MB | 46 | select DVB_DIB3000MB |
47 | depends on DVB_DIB3000MC || !DVB_DIB3000MC | ||
37 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT | 48 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT |
38 | help | 49 | help |
39 | Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by | 50 | Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by |
@@ -54,7 +65,7 @@ config DVB_USB_DIBUSB_MB_FAULTY | |||
54 | config DVB_USB_DIBUSB_MC | 65 | config DVB_USB_DIBUSB_MC |
55 | tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" | 66 | tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" |
56 | depends on DVB_USB | 67 | depends on DVB_USB |
57 | select DVB_DIB3000MC | 68 | select DVB_USB_DIB3000MC |
58 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT | 69 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT |
59 | help | 70 | help |
60 | Support for USB2.0 DVB-T receivers based on reference designs made by | 71 | Support for USB2.0 DVB-T receivers based on reference designs made by |
@@ -72,7 +83,7 @@ config DVB_USB_DIB0700 | |||
72 | select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT | 83 | select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT |
73 | select DVB_DIB7000M if MEDIA_SUBDRV_AUTOSELECT | 84 | select DVB_DIB7000M if MEDIA_SUBDRV_AUTOSELECT |
74 | select DVB_DIB8000 if MEDIA_SUBDRV_AUTOSELECT | 85 | select DVB_DIB8000 if MEDIA_SUBDRV_AUTOSELECT |
75 | select DVB_DIB3000MC if MEDIA_SUBDRV_AUTOSELECT | 86 | select DVB_USB_DIB3000MC if MEDIA_SUBDRV_AUTOSELECT |
76 | select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT | 87 | select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT |
77 | select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT | 88 | select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT |
78 | select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT | 89 | select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT |
@@ -99,7 +110,7 @@ config DVB_USB_UMT_010 | |||
99 | tristate "HanfTek UMT-010 DVB-T USB2.0 support" | 110 | tristate "HanfTek UMT-010 DVB-T USB2.0 support" |
100 | depends on DVB_USB | 111 | depends on DVB_USB |
101 | select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT | 112 | select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT |
102 | select DVB_DIB3000MC | 113 | select DVB_USB_DIB3000MC |
103 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT | 114 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT |
104 | select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT | 115 | select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT |
105 | help | 116 | help |
@@ -192,7 +203,7 @@ config DVB_USB_GP8PSK | |||
192 | config DVB_USB_NOVA_T_USB2 | 203 | config DVB_USB_NOVA_T_USB2 |
193 | tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" | 204 | tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" |
194 | depends on DVB_USB | 205 | depends on DVB_USB |
195 | select DVB_DIB3000MC | 206 | select DVB_USB_DIB3000MC |
196 | select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT | 207 | select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT |
197 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT | 208 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT |
198 | help | 209 | help |
diff --git a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile index acdd1efd4e74..2a7b5a963acf 100644 --- a/drivers/media/usb/dvb-usb/Makefile +++ b/drivers/media/usb/dvb-usb/Makefile | |||
@@ -16,20 +16,23 @@ obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o | |||
16 | 16 | ||
17 | dvb-usb-dibusb-common-objs := dibusb-common.o | 17 | dvb-usb-dibusb-common-objs := dibusb-common.o |
18 | 18 | ||
19 | dvb-usb-dibusb-mc-common-objs := dibusb-mc-common.o | ||
20 | obj-$(CONFIG_DVB_USB_DIB3000MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc-common.o | ||
21 | |||
19 | dvb-usb-a800-objs := a800.o | 22 | dvb-usb-a800-objs := a800.o |
20 | obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o | 23 | obj-$(CONFIG_DVB_USB_A800) += dvb-usb-a800.o |
21 | 24 | ||
22 | dvb-usb-dibusb-mb-objs := dibusb-mb.o | 25 | dvb-usb-dibusb-mb-objs := dibusb-mb.o |
23 | obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o | 26 | obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o |
24 | 27 | ||
25 | dvb-usb-dibusb-mc-objs := dibusb-mc.o | 28 | dvb-usb-dibusb-mc-objs := dibusb-mc.o |
26 | obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o | 29 | obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-mc.o |
27 | 30 | ||
28 | dvb-usb-nova-t-usb2-objs := nova-t-usb2.o | 31 | dvb-usb-nova-t-usb2-objs := nova-t-usb2.o |
29 | obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o | 32 | obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-nova-t-usb2.o |
30 | 33 | ||
31 | dvb-usb-umt-010-objs := umt-010.o | 34 | dvb-usb-umt-010-objs := umt-010.o |
32 | obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o | 35 | obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-umt-010.o |
33 | 36 | ||
34 | dvb-usb-m920x-objs := m920x.o | 37 | dvb-usb-m920x-objs := m920x.o |
35 | obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o | 38 | obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o |
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c index 26797979ebce..f3196658fb70 100644 --- a/drivers/media/usb/dvb-usb/dib0700_core.c +++ b/drivers/media/usb/dvb-usb/dib0700_core.c | |||
@@ -710,7 +710,6 @@ static void dib0700_rc_urb_completion(struct urb *purb) | |||
710 | 710 | ||
711 | switch (d->props.rc.core.protocol) { | 711 | switch (d->props.rc.core.protocol) { |
712 | case RC_BIT_NEC: | 712 | case RC_BIT_NEC: |
713 | protocol = RC_TYPE_NEC; | ||
714 | toggle = 0; | 713 | toggle = 0; |
715 | 714 | ||
716 | /* NEC protocol sends repeat code as 0 0 0 FF */ | 715 | /* NEC protocol sends repeat code as 0 0 0 FF */ |
@@ -728,16 +727,19 @@ static void dib0700_rc_urb_completion(struct urb *purb) | |||
728 | poll_reply->nec.not_system << 16 | | 727 | poll_reply->nec.not_system << 16 | |
729 | poll_reply->nec.data << 8 | | 728 | poll_reply->nec.data << 8 | |
730 | poll_reply->nec.not_data); | 729 | poll_reply->nec.not_data); |
730 | protocol = RC_TYPE_NEC32; | ||
731 | } else if ((poll_reply->nec.system ^ poll_reply->nec.not_system) != 0xff) { | 731 | } else if ((poll_reply->nec.system ^ poll_reply->nec.not_system) != 0xff) { |
732 | deb_data("NEC extended protocol\n"); | 732 | deb_data("NEC extended protocol\n"); |
733 | keycode = RC_SCANCODE_NECX(poll_reply->nec.system << 8 | | 733 | keycode = RC_SCANCODE_NECX(poll_reply->nec.system << 8 | |
734 | poll_reply->nec.not_system, | 734 | poll_reply->nec.not_system, |
735 | poll_reply->nec.data); | 735 | poll_reply->nec.data); |
736 | 736 | ||
737 | protocol = RC_TYPE_NECX; | ||
737 | } else { | 738 | } else { |
738 | deb_data("NEC normal protocol\n"); | 739 | deb_data("NEC normal protocol\n"); |
739 | keycode = RC_SCANCODE_NEC(poll_reply->nec.system, | 740 | keycode = RC_SCANCODE_NEC(poll_reply->nec.system, |
740 | poll_reply->nec.data); | 741 | poll_reply->nec.data); |
742 | protocol = RC_TYPE_NEC; | ||
741 | } | 743 | } |
742 | 744 | ||
743 | break; | 745 | break; |
diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index 6eea4e68891d..4b08c2a47ae2 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c | |||
@@ -184,164 +184,6 @@ int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) | |||
184 | } | 184 | } |
185 | EXPORT_SYMBOL(dibusb_read_eeprom_byte); | 185 | EXPORT_SYMBOL(dibusb_read_eeprom_byte); |
186 | 186 | ||
187 | #if IS_ENABLED(CONFIG_DVB_DIB3000MC) | ||
188 | |||
189 | /* 3000MC/P stuff */ | ||
190 | // Config Adjacent channels Perf -cal22 | ||
191 | static struct dibx000_agc_config dib3000p_mt2060_agc_config = { | ||
192 | .band_caps = BAND_VHF | BAND_UHF, | ||
193 | .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), | ||
194 | |||
195 | .agc1_max = 48497, | ||
196 | .agc1_min = 23593, | ||
197 | .agc2_max = 46531, | ||
198 | .agc2_min = 24904, | ||
199 | |||
200 | .agc1_pt1 = 0x65, | ||
201 | .agc1_pt2 = 0x69, | ||
202 | |||
203 | .agc1_slope1 = 0x51, | ||
204 | .agc1_slope2 = 0x27, | ||
205 | |||
206 | .agc2_pt1 = 0, | ||
207 | .agc2_pt2 = 0x33, | ||
208 | |||
209 | .agc2_slope1 = 0x35, | ||
210 | .agc2_slope2 = 0x37, | ||
211 | }; | ||
212 | |||
213 | static struct dib3000mc_config stk3000p_dib3000p_config = { | ||
214 | &dib3000p_mt2060_agc_config, | ||
215 | |||
216 | .max_time = 0x196, | ||
217 | .ln_adc_level = 0x1cc7, | ||
218 | |||
219 | .output_mpeg2_in_188_bytes = 1, | ||
220 | |||
221 | .agc_command1 = 1, | ||
222 | .agc_command2 = 1, | ||
223 | }; | ||
224 | |||
225 | static struct dibx000_agc_config dib3000p_panasonic_agc_config = { | ||
226 | .band_caps = BAND_VHF | BAND_UHF, | ||
227 | .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), | ||
228 | |||
229 | .agc1_max = 56361, | ||
230 | .agc1_min = 22282, | ||
231 | .agc2_max = 47841, | ||
232 | .agc2_min = 36045, | ||
233 | |||
234 | .agc1_pt1 = 0x3b, | ||
235 | .agc1_pt2 = 0x6b, | ||
236 | |||
237 | .agc1_slope1 = 0x55, | ||
238 | .agc1_slope2 = 0x1d, | ||
239 | |||
240 | .agc2_pt1 = 0, | ||
241 | .agc2_pt2 = 0x0a, | ||
242 | |||
243 | .agc2_slope1 = 0x95, | ||
244 | .agc2_slope2 = 0x1e, | ||
245 | }; | ||
246 | |||
247 | static struct dib3000mc_config mod3000p_dib3000p_config = { | ||
248 | &dib3000p_panasonic_agc_config, | ||
249 | |||
250 | .max_time = 0x51, | ||
251 | .ln_adc_level = 0x1cc7, | ||
252 | |||
253 | .output_mpeg2_in_188_bytes = 1, | ||
254 | |||
255 | .agc_command1 = 1, | ||
256 | .agc_command2 = 1, | ||
257 | }; | ||
258 | |||
259 | int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) | ||
260 | { | ||
261 | if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON && | ||
262 | le16_to_cpu(adap->dev->udev->descriptor.idProduct) == | ||
263 | USB_PID_LITEON_DVB_T_WARM) { | ||
264 | msleep(1000); | ||
265 | } | ||
266 | |||
267 | adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, | ||
268 | &adap->dev->i2c_adap, | ||
269 | DEFAULT_DIB3000P_I2C_ADDRESS, | ||
270 | &mod3000p_dib3000p_config); | ||
271 | if ((adap->fe_adap[0].fe) == NULL) | ||
272 | adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, | ||
273 | &adap->dev->i2c_adap, | ||
274 | DEFAULT_DIB3000MC_I2C_ADDRESS, | ||
275 | &mod3000p_dib3000p_config); | ||
276 | if ((adap->fe_adap[0].fe) != NULL) { | ||
277 | if (adap->priv != NULL) { | ||
278 | struct dibusb_state *st = adap->priv; | ||
279 | st->ops.pid_parse = dib3000mc_pid_parse; | ||
280 | st->ops.pid_ctrl = dib3000mc_pid_control; | ||
281 | } | ||
282 | return 0; | ||
283 | } | ||
284 | return -ENODEV; | ||
285 | } | ||
286 | EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach); | ||
287 | |||
288 | static struct mt2060_config stk3000p_mt2060_config = { | ||
289 | 0x60 | ||
290 | }; | ||
291 | |||
292 | int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) | ||
293 | { | ||
294 | struct dibusb_state *st = adap->priv; | ||
295 | u8 a,b; | ||
296 | u16 if1 = 1220; | ||
297 | struct i2c_adapter *tun_i2c; | ||
298 | |||
299 | // First IF calibration for Liteon Sticks | ||
300 | if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON && | ||
301 | le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_LITEON_DVB_T_WARM) { | ||
302 | |||
303 | dibusb_read_eeprom_byte(adap->dev,0x7E,&a); | ||
304 | dibusb_read_eeprom_byte(adap->dev,0x7F,&b); | ||
305 | |||
306 | if (a == 0x00) | ||
307 | if1 += b; | ||
308 | else if (a == 0x80) | ||
309 | if1 -= b; | ||
310 | else | ||
311 | warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b); | ||
312 | |||
313 | } else if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_DIBCOM && | ||
314 | le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_DIBCOM_MOD3001_WARM) { | ||
315 | u8 desc; | ||
316 | dibusb_read_eeprom_byte(adap->dev, 7, &desc); | ||
317 | if (desc == 2) { | ||
318 | a = 127; | ||
319 | do { | ||
320 | dibusb_read_eeprom_byte(adap->dev, a, &desc); | ||
321 | a--; | ||
322 | } while (a > 7 && (desc == 0xff || desc == 0x00)); | ||
323 | if (desc & 0x80) | ||
324 | if1 -= (0xff - desc); | ||
325 | else | ||
326 | if1 += desc; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1); | ||
331 | if (dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { | ||
332 | /* not found - use panasonic pll parameters */ | ||
333 | if (dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) | ||
334 | return -ENOMEM; | ||
335 | } else { | ||
336 | st->mt2060_present = 1; | ||
337 | /* set the correct parameters for the dib3000p */ | ||
338 | dib3000mc_set_config(adap->fe_adap[0].fe, &stk3000p_dib3000p_config); | ||
339 | } | ||
340 | return 0; | ||
341 | } | ||
342 | EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach); | ||
343 | #endif | ||
344 | |||
345 | /* | 187 | /* |
346 | * common remote control stuff | 188 | * common remote control stuff |
347 | */ | 189 | */ |
diff --git a/drivers/media/usb/dvb-usb/dibusb-mc-common.c b/drivers/media/usb/dvb-usb/dibusb-mc-common.c new file mode 100644 index 000000000000..d66f56cc46a5 --- /dev/null +++ b/drivers/media/usb/dvb-usb/dibusb-mc-common.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* Common methods for dibusb-based-receivers. | ||
2 | * | ||
3 | * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the Free | ||
7 | * Software Foundation, version 2. | ||
8 | * | ||
9 | * see Documentation/dvb/README.dvb-usb for more information | ||
10 | */ | ||
11 | |||
12 | #include <linux/kconfig.h> | ||
13 | #include "dibusb.h" | ||
14 | |||
15 | /* 3000MC/P stuff */ | ||
16 | // Config Adjacent channels Perf -cal22 | ||
17 | static struct dibx000_agc_config dib3000p_mt2060_agc_config = { | ||
18 | .band_caps = BAND_VHF | BAND_UHF, | ||
19 | .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), | ||
20 | |||
21 | .agc1_max = 48497, | ||
22 | .agc1_min = 23593, | ||
23 | .agc2_max = 46531, | ||
24 | .agc2_min = 24904, | ||
25 | |||
26 | .agc1_pt1 = 0x65, | ||
27 | .agc1_pt2 = 0x69, | ||
28 | |||
29 | .agc1_slope1 = 0x51, | ||
30 | .agc1_slope2 = 0x27, | ||
31 | |||
32 | .agc2_pt1 = 0, | ||
33 | .agc2_pt2 = 0x33, | ||
34 | |||
35 | .agc2_slope1 = 0x35, | ||
36 | .agc2_slope2 = 0x37, | ||
37 | }; | ||
38 | |||
39 | static struct dib3000mc_config stk3000p_dib3000p_config = { | ||
40 | &dib3000p_mt2060_agc_config, | ||
41 | |||
42 | .max_time = 0x196, | ||
43 | .ln_adc_level = 0x1cc7, | ||
44 | |||
45 | .output_mpeg2_in_188_bytes = 1, | ||
46 | |||
47 | .agc_command1 = 1, | ||
48 | .agc_command2 = 1, | ||
49 | }; | ||
50 | |||
51 | static struct dibx000_agc_config dib3000p_panasonic_agc_config = { | ||
52 | .band_caps = BAND_VHF | BAND_UHF, | ||
53 | .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), | ||
54 | |||
55 | .agc1_max = 56361, | ||
56 | .agc1_min = 22282, | ||
57 | .agc2_max = 47841, | ||
58 | .agc2_min = 36045, | ||
59 | |||
60 | .agc1_pt1 = 0x3b, | ||
61 | .agc1_pt2 = 0x6b, | ||
62 | |||
63 | .agc1_slope1 = 0x55, | ||
64 | .agc1_slope2 = 0x1d, | ||
65 | |||
66 | .agc2_pt1 = 0, | ||
67 | .agc2_pt2 = 0x0a, | ||
68 | |||
69 | .agc2_slope1 = 0x95, | ||
70 | .agc2_slope2 = 0x1e, | ||
71 | }; | ||
72 | |||
73 | static struct dib3000mc_config mod3000p_dib3000p_config = { | ||
74 | &dib3000p_panasonic_agc_config, | ||
75 | |||
76 | .max_time = 0x51, | ||
77 | .ln_adc_level = 0x1cc7, | ||
78 | |||
79 | .output_mpeg2_in_188_bytes = 1, | ||
80 | |||
81 | .agc_command1 = 1, | ||
82 | .agc_command2 = 1, | ||
83 | }; | ||
84 | |||
85 | int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) | ||
86 | { | ||
87 | if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON && | ||
88 | le16_to_cpu(adap->dev->udev->descriptor.idProduct) == | ||
89 | USB_PID_LITEON_DVB_T_WARM) { | ||
90 | msleep(1000); | ||
91 | } | ||
92 | |||
93 | adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, | ||
94 | &adap->dev->i2c_adap, | ||
95 | DEFAULT_DIB3000P_I2C_ADDRESS, | ||
96 | &mod3000p_dib3000p_config); | ||
97 | if ((adap->fe_adap[0].fe) == NULL) | ||
98 | adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, | ||
99 | &adap->dev->i2c_adap, | ||
100 | DEFAULT_DIB3000MC_I2C_ADDRESS, | ||
101 | &mod3000p_dib3000p_config); | ||
102 | if ((adap->fe_adap[0].fe) != NULL) { | ||
103 | if (adap->priv != NULL) { | ||
104 | struct dibusb_state *st = adap->priv; | ||
105 | st->ops.pid_parse = dib3000mc_pid_parse; | ||
106 | st->ops.pid_ctrl = dib3000mc_pid_control; | ||
107 | } | ||
108 | return 0; | ||
109 | } | ||
110 | return -ENODEV; | ||
111 | } | ||
112 | EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach); | ||
113 | |||
114 | static struct mt2060_config stk3000p_mt2060_config = { | ||
115 | 0x60 | ||
116 | }; | ||
117 | |||
118 | int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) | ||
119 | { | ||
120 | struct dibusb_state *st = adap->priv; | ||
121 | u8 a,b; | ||
122 | u16 if1 = 1220; | ||
123 | struct i2c_adapter *tun_i2c; | ||
124 | |||
125 | // First IF calibration for Liteon Sticks | ||
126 | if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON && | ||
127 | le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_LITEON_DVB_T_WARM) { | ||
128 | |||
129 | dibusb_read_eeprom_byte(adap->dev,0x7E,&a); | ||
130 | dibusb_read_eeprom_byte(adap->dev,0x7F,&b); | ||
131 | |||
132 | if (a == 0x00) | ||
133 | if1 += b; | ||
134 | else if (a == 0x80) | ||
135 | if1 -= b; | ||
136 | else | ||
137 | warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b); | ||
138 | |||
139 | } else if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_DIBCOM && | ||
140 | le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_DIBCOM_MOD3001_WARM) { | ||
141 | u8 desc; | ||
142 | dibusb_read_eeprom_byte(adap->dev, 7, &desc); | ||
143 | if (desc == 2) { | ||
144 | a = 127; | ||
145 | do { | ||
146 | dibusb_read_eeprom_byte(adap->dev, a, &desc); | ||
147 | a--; | ||
148 | } while (a > 7 && (desc == 0xff || desc == 0x00)); | ||
149 | if (desc & 0x80) | ||
150 | if1 -= (0xff - desc); | ||
151 | else | ||
152 | if1 += desc; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1); | ||
157 | if (dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { | ||
158 | /* not found - use panasonic pll parameters */ | ||
159 | if (dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) | ||
160 | return -ENOMEM; | ||
161 | } else { | ||
162 | st->mt2060_present = 1; | ||
163 | /* set the correct parameters for the dib3000p */ | ||
164 | dib3000mc_set_config(adap->fe_adap[0].fe, &stk3000p_dib3000p_config); | ||
165 | } | ||
166 | return 0; | ||
167 | } | ||
168 | EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach); | ||
diff --git a/drivers/media/usb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c index be633ece4194..d2a01b50af0d 100644 --- a/drivers/media/usb/dvb-usb/dtt200u.c +++ b/drivers/media/usb/dvb-usb/dtt200u.c | |||
@@ -62,18 +62,21 @@ static int dtt200u_rc_query(struct dvb_usb_device *d) | |||
62 | 62 | ||
63 | dvb_usb_generic_rw(d,&cmd,1,key,5,0); | 63 | dvb_usb_generic_rw(d,&cmd,1,key,5,0); |
64 | if (key[0] == 1) { | 64 | if (key[0] == 1) { |
65 | enum rc_type proto = RC_TYPE_NEC; | ||
66 | |||
65 | scancode = key[1]; | 67 | scancode = key[1]; |
66 | if ((u8) ~key[1] != key[2]) { | 68 | if ((u8) ~key[1] != key[2]) { |
67 | /* Extended NEC */ | 69 | /* Extended NEC */ |
68 | scancode = scancode << 8; | 70 | scancode = scancode << 8; |
69 | scancode |= key[2]; | 71 | scancode |= key[2]; |
72 | proto = RC_TYPE_NECX; | ||
70 | } | 73 | } |
71 | scancode = scancode << 8; | 74 | scancode = scancode << 8; |
72 | scancode |= key[3]; | 75 | scancode |= key[3]; |
73 | 76 | ||
74 | /* Check command checksum is ok */ | 77 | /* Check command checksum is ok */ |
75 | if ((u8) ~key[3] == key[4]) | 78 | if ((u8) ~key[3] == key[4]) |
76 | rc_keydown(d->rc_dev, RC_TYPE_NEC, scancode, 0); | 79 | rc_keydown(d->rc_dev, proto, scancode, 0); |
77 | else | 80 | else |
78 | rc_keyup(d->rc_dev); | 81 | rc_keyup(d->rc_dev); |
79 | } else if (key[0] == 2) { | 82 | } else if (key[0] == 2) { |
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 78f3687772bf..e11fe46a547c 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c | |||
@@ -695,7 +695,7 @@ static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev, | |||
695 | /* | 695 | /* |
696 | * register/unregister code and data | 696 | * register/unregister code and data |
697 | */ | 697 | */ |
698 | static struct snd_pcm_ops snd_em28xx_pcm_capture = { | 698 | static const struct snd_pcm_ops snd_em28xx_pcm_capture = { |
699 | .open = snd_em28xx_capture_open, | 699 | .open = snd_em28xx_capture_open, |
700 | .close = snd_em28xx_pcm_close, | 700 | .close = snd_em28xx_pcm_close, |
701 | .ioctl = snd_pcm_lib_ioctl, | 701 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 1a9e1e556706..8b690ac908a4 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c | |||
@@ -855,7 +855,7 @@ static u32 functionality(struct i2c_adapter *i2c_adap) | |||
855 | return 0; | 855 | return 0; |
856 | } | 856 | } |
857 | 857 | ||
858 | static struct i2c_algorithm em28xx_algo = { | 858 | static const struct i2c_algorithm em28xx_algo = { |
859 | .master_xfer = em28xx_i2c_xfer, | 859 | .master_xfer = em28xx_i2c_xfer, |
860 | .functionality = functionality, | 860 | .functionality = functionality, |
861 | }; | 861 | }; |
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 7968695217f3..1f7fa059eb34 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c | |||
@@ -1204,7 +1204,7 @@ buffer_queue(struct vb2_buffer *vb) | |||
1204 | spin_unlock_irqrestore(&dev->slock, flags); | 1204 | spin_unlock_irqrestore(&dev->slock, flags); |
1205 | } | 1205 | } |
1206 | 1206 | ||
1207 | static struct vb2_ops em28xx_video_qops = { | 1207 | static const struct vb2_ops em28xx_video_qops = { |
1208 | .queue_setup = queue_setup, | 1208 | .queue_setup = queue_setup, |
1209 | .buf_prepare = buffer_prepare, | 1209 | .buf_prepare = buffer_prepare, |
1210 | .buf_queue = buffer_queue, | 1210 | .buf_queue = buffer_queue, |
diff --git a/drivers/media/usb/go7007/go7007-i2c.c b/drivers/media/usb/go7007/go7007-i2c.c index 55addfa855d4..c084bf794b56 100644 --- a/drivers/media/usb/go7007/go7007-i2c.c +++ b/drivers/media/usb/go7007/go7007-i2c.c | |||
@@ -191,7 +191,7 @@ static u32 go7007_functionality(struct i2c_adapter *adapter) | |||
191 | return I2C_FUNC_SMBUS_BYTE_DATA; | 191 | return I2C_FUNC_SMBUS_BYTE_DATA; |
192 | } | 192 | } |
193 | 193 | ||
194 | static struct i2c_algorithm go7007_algo = { | 194 | static const struct i2c_algorithm go7007_algo = { |
195 | .smbus_xfer = go7007_smbus_xfer, | 195 | .smbus_xfer = go7007_smbus_xfer, |
196 | .master_xfer = go7007_i2c_master_xfer, | 196 | .master_xfer = go7007_i2c_master_xfer, |
197 | .functionality = go7007_functionality, | 197 | .functionality = go7007_functionality, |
diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c index 14d3f8c1ce4a..ed9bcaf08d5e 100644 --- a/drivers/media/usb/go7007/go7007-usb.c +++ b/drivers/media/usb/go7007/go7007-usb.c | |||
@@ -1032,7 +1032,7 @@ static u32 go7007_usb_functionality(struct i2c_adapter *adapter) | |||
1032 | return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK; | 1032 | return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK; |
1033 | } | 1033 | } |
1034 | 1034 | ||
1035 | static struct i2c_algorithm go7007_usb_algo = { | 1035 | static const struct i2c_algorithm go7007_usb_algo = { |
1036 | .master_xfer = go7007_usb_i2c_master_xfer, | 1036 | .master_xfer = go7007_usb_i2c_master_xfer, |
1037 | .functionality = go7007_usb_functionality, | 1037 | .functionality = go7007_usb_functionality, |
1038 | }; | 1038 | }; |
diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index af8458996d91..4eaba0c24629 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c | |||
@@ -477,7 +477,7 @@ static void go7007_stop_streaming(struct vb2_queue *q) | |||
477 | go7007_write_addr(go, 0x3c82, 0x000d); | 477 | go7007_write_addr(go, 0x3c82, 0x000d); |
478 | } | 478 | } |
479 | 479 | ||
480 | static struct vb2_ops go7007_video_qops = { | 480 | static const struct vb2_ops go7007_video_qops = { |
481 | .queue_setup = go7007_queue_setup, | 481 | .queue_setup = go7007_queue_setup, |
482 | .buf_queue = go7007_buf_queue, | 482 | .buf_queue = go7007_buf_queue, |
483 | .buf_prepare = go7007_buf_prepare, | 483 | .buf_prepare = go7007_buf_prepare, |
diff --git a/drivers/media/usb/go7007/snd-go7007.c b/drivers/media/usb/go7007/snd-go7007.c index d22d7d574672..070871fb1fc4 100644 --- a/drivers/media/usb/go7007/snd-go7007.c +++ b/drivers/media/usb/go7007/snd-go7007.c | |||
@@ -198,7 +198,7 @@ static struct page *go7007_snd_pcm_page(struct snd_pcm_substream *substream, | |||
198 | return vmalloc_to_page(substream->runtime->dma_area + offset); | 198 | return vmalloc_to_page(substream->runtime->dma_area + offset); |
199 | } | 199 | } |
200 | 200 | ||
201 | static struct snd_pcm_ops go7007_snd_capture_ops = { | 201 | static const struct snd_pcm_ops go7007_snd_capture_ops = { |
202 | .open = go7007_snd_capture_open, | 202 | .open = go7007_snd_capture_open, |
203 | .close = go7007_snd_capture_close, | 203 | .close = go7007_snd_capture_close, |
204 | .ioctl = snd_pcm_lib_ioctl, | 204 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/drivers/media/usb/gspca/finepix.c b/drivers/media/usb/gspca/finepix.c index 52bdb569760b..ae9a55d7bbbb 100644 --- a/drivers/media/usb/gspca/finepix.c +++ b/drivers/media/usb/gspca/finepix.c | |||
@@ -41,7 +41,6 @@ struct usb_fpix { | |||
41 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 41 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
42 | 42 | ||
43 | struct work_struct work_struct; | 43 | struct work_struct work_struct; |
44 | struct workqueue_struct *work_thread; | ||
45 | }; | 44 | }; |
46 | 45 | ||
47 | /* Delay after which claim the next frame. If the delay is too small, | 46 | /* Delay after which claim the next frame. If the delay is too small, |
@@ -226,9 +225,7 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
226 | /* Again, reset bulk in endpoint */ | 225 | /* Again, reset bulk in endpoint */ |
227 | usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe); | 226 | usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe); |
228 | 227 | ||
229 | /* Start the workqueue function to do the streaming */ | 228 | schedule_work(&dev->work_struct); |
230 | dev->work_thread = create_singlethread_workqueue(MODULE_NAME); | ||
231 | queue_work(dev->work_thread, &dev->work_struct); | ||
232 | 229 | ||
233 | return 0; | 230 | return 0; |
234 | } | 231 | } |
@@ -241,9 +238,8 @@ static void sd_stop0(struct gspca_dev *gspca_dev) | |||
241 | 238 | ||
242 | /* wait for the work queue to terminate */ | 239 | /* wait for the work queue to terminate */ |
243 | mutex_unlock(&gspca_dev->usb_lock); | 240 | mutex_unlock(&gspca_dev->usb_lock); |
244 | destroy_workqueue(dev->work_thread); | 241 | flush_work(&dev->work_struct); |
245 | mutex_lock(&gspca_dev->usb_lock); | 242 | mutex_lock(&gspca_dev->usb_lock); |
246 | dev->work_thread = NULL; | ||
247 | } | 243 | } |
248 | 244 | ||
249 | /* Table of supported USB devices */ | 245 | /* Table of supported USB devices */ |
diff --git a/drivers/media/usb/gspca/jl2005bcd.c b/drivers/media/usb/gspca/jl2005bcd.c index 5b481fa43099..ac295f04bd18 100644 --- a/drivers/media/usb/gspca/jl2005bcd.c +++ b/drivers/media/usb/gspca/jl2005bcd.c | |||
@@ -45,7 +45,6 @@ struct sd { | |||
45 | const struct v4l2_pix_format *cap_mode; | 45 | const struct v4l2_pix_format *cap_mode; |
46 | /* Driver stuff */ | 46 | /* Driver stuff */ |
47 | struct work_struct work_struct; | 47 | struct work_struct work_struct; |
48 | struct workqueue_struct *work_thread; | ||
49 | u8 frame_brightness; | 48 | u8 frame_brightness; |
50 | int block_size; /* block size of camera */ | 49 | int block_size; /* block size of camera */ |
51 | int vga; /* 1 if vga cam, 0 if cif cam */ | 50 | int vga; /* 1 if vga cam, 0 if cif cam */ |
@@ -477,9 +476,7 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
477 | return -1; | 476 | return -1; |
478 | } | 477 | } |
479 | 478 | ||
480 | /* Start the workqueue function to do the streaming */ | 479 | schedule_work(&sd->work_struct); |
481 | sd->work_thread = create_singlethread_workqueue(MODULE_NAME); | ||
482 | queue_work(sd->work_thread, &sd->work_struct); | ||
483 | 480 | ||
484 | return 0; | 481 | return 0; |
485 | } | 482 | } |
@@ -493,8 +490,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev) | |||
493 | /* wait for the work queue to terminate */ | 490 | /* wait for the work queue to terminate */ |
494 | mutex_unlock(&gspca_dev->usb_lock); | 491 | mutex_unlock(&gspca_dev->usb_lock); |
495 | /* This waits for sq905c_dostream to finish */ | 492 | /* This waits for sq905c_dostream to finish */ |
496 | destroy_workqueue(dev->work_thread); | 493 | flush_work(&dev->work_struct); |
497 | dev->work_thread = NULL; | ||
498 | mutex_lock(&gspca_dev->usb_lock); | 494 | mutex_lock(&gspca_dev->usb_lock); |
499 | } | 495 | } |
500 | 496 | ||
diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c index fd1c8706d86a..d49d76ec1421 100644 --- a/drivers/media/usb/gspca/sonixj.c +++ b/drivers/media/usb/gspca/sonixj.c | |||
@@ -54,7 +54,6 @@ struct sd { | |||
54 | u32 exposure; | 54 | u32 exposure; |
55 | 55 | ||
56 | struct work_struct work; | 56 | struct work_struct work; |
57 | struct workqueue_struct *work_thread; | ||
58 | 57 | ||
59 | u32 pktsz; /* (used by pkt_scan) */ | 58 | u32 pktsz; /* (used by pkt_scan) */ |
60 | u16 npkt; | 59 | u16 npkt; |
@@ -2485,7 +2484,6 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
2485 | 2484 | ||
2486 | sd->pktsz = sd->npkt = 0; | 2485 | sd->pktsz = sd->npkt = 0; |
2487 | sd->nchg = sd->short_mark = 0; | 2486 | sd->nchg = sd->short_mark = 0; |
2488 | sd->work_thread = create_singlethread_workqueue(MODULE_NAME); | ||
2489 | 2487 | ||
2490 | return gspca_dev->usb_err; | 2488 | return gspca_dev->usb_err; |
2491 | } | 2489 | } |
@@ -2569,12 +2567,9 @@ static void sd_stop0(struct gspca_dev *gspca_dev) | |||
2569 | { | 2567 | { |
2570 | struct sd *sd = (struct sd *) gspca_dev; | 2568 | struct sd *sd = (struct sd *) gspca_dev; |
2571 | 2569 | ||
2572 | if (sd->work_thread != NULL) { | 2570 | mutex_unlock(&gspca_dev->usb_lock); |
2573 | mutex_unlock(&gspca_dev->usb_lock); | 2571 | flush_work(&sd->work); |
2574 | destroy_workqueue(sd->work_thread); | 2572 | mutex_lock(&gspca_dev->usb_lock); |
2575 | mutex_lock(&gspca_dev->usb_lock); | ||
2576 | sd->work_thread = NULL; | ||
2577 | } | ||
2578 | } | 2573 | } |
2579 | 2574 | ||
2580 | static void do_autogain(struct gspca_dev *gspca_dev) | 2575 | static void do_autogain(struct gspca_dev *gspca_dev) |
@@ -2785,7 +2780,7 @@ marker_found: | |||
2785 | new_qual = QUALITY_MAX; | 2780 | new_qual = QUALITY_MAX; |
2786 | if (new_qual != sd->quality) { | 2781 | if (new_qual != sd->quality) { |
2787 | sd->quality = new_qual; | 2782 | sd->quality = new_qual; |
2788 | queue_work(sd->work_thread, &sd->work); | 2783 | schedule_work(&sd->work); |
2789 | } | 2784 | } |
2790 | } | 2785 | } |
2791 | } else { | 2786 | } else { |
diff --git a/drivers/media/usb/gspca/vicam.c b/drivers/media/usb/gspca/vicam.c index 103f6c4236b0..8860510c2f9c 100644 --- a/drivers/media/usb/gspca/vicam.c +++ b/drivers/media/usb/gspca/vicam.c | |||
@@ -47,7 +47,6 @@ MODULE_FIRMWARE(VICAM_FIRMWARE); | |||
47 | struct sd { | 47 | struct sd { |
48 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 48 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
49 | struct work_struct work_struct; | 49 | struct work_struct work_struct; |
50 | struct workqueue_struct *work_thread; | ||
51 | }; | 50 | }; |
52 | 51 | ||
53 | /* The vicam sensor has a resolution of 512 x 244, with I believe square | 52 | /* The vicam sensor has a resolution of 512 x 244, with I believe square |
@@ -278,9 +277,7 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
278 | if (ret < 0) | 277 | if (ret < 0) |
279 | return ret; | 278 | return ret; |
280 | 279 | ||
281 | /* Start the workqueue function to do the streaming */ | 280 | schedule_work(&sd->work_struct); |
282 | sd->work_thread = create_singlethread_workqueue(MODULE_NAME); | ||
283 | queue_work(sd->work_thread, &sd->work_struct); | ||
284 | 281 | ||
285 | return 0; | 282 | return 0; |
286 | } | 283 | } |
@@ -294,8 +291,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev) | |||
294 | /* wait for the work queue to terminate */ | 291 | /* wait for the work queue to terminate */ |
295 | mutex_unlock(&gspca_dev->usb_lock); | 292 | mutex_unlock(&gspca_dev->usb_lock); |
296 | /* This waits for vicam_dostream to finish */ | 293 | /* This waits for vicam_dostream to finish */ |
297 | destroy_workqueue(dev->work_thread); | 294 | flush_work(&dev->work_struct); |
298 | dev->work_thread = NULL; | ||
299 | mutex_lock(&gspca_dev->usb_lock); | 295 | mutex_lock(&gspca_dev->usb_lock); |
300 | 296 | ||
301 | if (gspca_dev->present) | 297 | if (gspca_dev->present) |
diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index c2c8d12e9498..d9a525260511 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c | |||
@@ -129,7 +129,7 @@ struct hackrf_dev { | |||
129 | struct list_head rx_buffer_list; | 129 | struct list_head rx_buffer_list; |
130 | struct list_head tx_buffer_list; | 130 | struct list_head tx_buffer_list; |
131 | spinlock_t buffer_list_lock; /* Protects buffer_list */ | 131 | spinlock_t buffer_list_lock; /* Protects buffer_list */ |
132 | unsigned sequence; /* Buffer sequence counter */ | 132 | unsigned int sequence; /* Buffer sequence counter */ |
133 | unsigned int vb_full; /* vb is full and packets dropped */ | 133 | unsigned int vb_full; /* vb is full and packets dropped */ |
134 | unsigned int vb_empty; /* vb is empty and packets dropped */ | 134 | unsigned int vb_empty; /* vb is empty and packets dropped */ |
135 | 135 | ||
@@ -891,7 +891,7 @@ static void hackrf_stop_streaming(struct vb2_queue *vq) | |||
891 | mutex_unlock(&dev->v4l2_lock); | 891 | mutex_unlock(&dev->v4l2_lock); |
892 | } | 892 | } |
893 | 893 | ||
894 | static struct vb2_ops hackrf_vb2_ops = { | 894 | static const struct vb2_ops hackrf_vb2_ops = { |
895 | .queue_setup = hackrf_queue_setup, | 895 | .queue_setup = hackrf_queue_setup, |
896 | .buf_queue = hackrf_buf_queue, | 896 | .buf_queue = hackrf_buf_queue, |
897 | .start_streaming = hackrf_start_streaming, | 897 | .start_streaming = hackrf_start_streaming, |
diff --git a/drivers/media/usb/hdpvr/hdpvr-i2c.c b/drivers/media/usb/hdpvr/hdpvr-i2c.c index a38f58c4c6bf..9b641c4d4431 100644 --- a/drivers/media/usb/hdpvr/hdpvr-i2c.c +++ b/drivers/media/usb/hdpvr/hdpvr-i2c.c | |||
@@ -55,7 +55,7 @@ struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev) | |||
55 | /* Our default information for ir-kbd-i2c.c to use */ | 55 | /* Our default information for ir-kbd-i2c.c to use */ |
56 | init_data->ir_codes = RC_MAP_HAUPPAUGE; | 56 | init_data->ir_codes = RC_MAP_HAUPPAUGE; |
57 | init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; | 57 | init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; |
58 | init_data->type = RC_BIT_RC5; | 58 | init_data->type = RC_BIT_RC5 | RC_BIT_RC6_MCE | RC_BIT_RC6_6A_32; |
59 | init_data->name = "HD-PVR"; | 59 | init_data->name = "HD-PVR"; |
60 | init_data->polling_interval = 405; /* ms, duplicated from Windows */ | 60 | init_data->polling_interval = 405; /* ms, duplicated from Windows */ |
61 | hdpvr_ir_rx_i2c_board_info.platform_data = init_data; | 61 | hdpvr_ir_rx_i2c_board_info.platform_data = init_data; |
@@ -180,7 +180,7 @@ static u32 hdpvr_functionality(struct i2c_adapter *adapter) | |||
180 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | 180 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; |
181 | } | 181 | } |
182 | 182 | ||
183 | static struct i2c_algorithm hdpvr_algo = { | 183 | static const struct i2c_algorithm hdpvr_algo = { |
184 | .master_xfer = hdpvr_transfer, | 184 | .master_xfer = hdpvr_transfer, |
185 | .functionality = hdpvr_functionality, | 185 | .functionality = hdpvr_functionality, |
186 | }; | 186 | }; |
diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 367eb7e2a31d..bb3d31e2a0b5 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c | |||
@@ -897,7 +897,7 @@ static void msi2500_stop_streaming(struct vb2_queue *vq) | |||
897 | mutex_unlock(&dev->v4l2_lock); | 897 | mutex_unlock(&dev->v4l2_lock); |
898 | } | 898 | } |
899 | 899 | ||
900 | static struct vb2_ops msi2500_vb2_ops = { | 900 | static const struct vb2_ops msi2500_vb2_ops = { |
901 | .queue_setup = msi2500_queue_setup, | 901 | .queue_setup = msi2500_queue_setup, |
902 | .buf_queue = msi2500_buf_queue, | 902 | .buf_queue = msi2500_buf_queue, |
903 | .start_streaming = msi2500_start_streaming, | 903 | .start_streaming = msi2500_start_streaming, |
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h index 60141b16d731..23473a21319c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h | |||
@@ -170,7 +170,6 @@ struct pvr2_hdw { | |||
170 | const struct pvr2_device_desc *hdw_desc; | 170 | const struct pvr2_device_desc *hdw_desc; |
171 | 171 | ||
172 | /* Kernel worker thread handling */ | 172 | /* Kernel worker thread handling */ |
173 | struct workqueue_struct *workqueue; | ||
174 | struct work_struct workpoll; /* Update driver state */ | 173 | struct work_struct workpoll; /* Update driver state */ |
175 | 174 | ||
176 | /* Video spigot */ | 175 | /* Video spigot */ |
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index fe20fe4f2330..1eb4f7ba2967 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c | |||
@@ -2624,7 +2624,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, | |||
2624 | if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1; | 2624 | if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1; |
2625 | hdw->name[cnt1] = 0; | 2625 | hdw->name[cnt1] = 0; |
2626 | 2626 | ||
2627 | hdw->workqueue = create_singlethread_workqueue(hdw->name); | ||
2628 | INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll); | 2627 | INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll); |
2629 | 2628 | ||
2630 | pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", | 2629 | pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", |
@@ -2651,11 +2650,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, | |||
2651 | del_timer_sync(&hdw->decoder_stabilization_timer); | 2650 | del_timer_sync(&hdw->decoder_stabilization_timer); |
2652 | del_timer_sync(&hdw->encoder_run_timer); | 2651 | del_timer_sync(&hdw->encoder_run_timer); |
2653 | del_timer_sync(&hdw->encoder_wait_timer); | 2652 | del_timer_sync(&hdw->encoder_wait_timer); |
2654 | if (hdw->workqueue) { | 2653 | flush_work(&hdw->workpoll); |
2655 | flush_workqueue(hdw->workqueue); | ||
2656 | destroy_workqueue(hdw->workqueue); | ||
2657 | hdw->workqueue = NULL; | ||
2658 | } | ||
2659 | usb_free_urb(hdw->ctl_read_urb); | 2654 | usb_free_urb(hdw->ctl_read_urb); |
2660 | usb_free_urb(hdw->ctl_write_urb); | 2655 | usb_free_urb(hdw->ctl_write_urb); |
2661 | kfree(hdw->ctl_read_buffer); | 2656 | kfree(hdw->ctl_read_buffer); |
@@ -2712,11 +2707,7 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) | |||
2712 | { | 2707 | { |
2713 | if (!hdw) return; | 2708 | if (!hdw) return; |
2714 | pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); | 2709 | pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); |
2715 | if (hdw->workqueue) { | 2710 | flush_work(&hdw->workpoll); |
2716 | flush_workqueue(hdw->workqueue); | ||
2717 | destroy_workqueue(hdw->workqueue); | ||
2718 | hdw->workqueue = NULL; | ||
2719 | } | ||
2720 | del_timer_sync(&hdw->quiescent_timer); | 2711 | del_timer_sync(&hdw->quiescent_timer); |
2721 | del_timer_sync(&hdw->decoder_stabilization_timer); | 2712 | del_timer_sync(&hdw->decoder_stabilization_timer); |
2722 | del_timer_sync(&hdw->encoder_run_timer); | 2713 | del_timer_sync(&hdw->encoder_run_timer); |
@@ -4443,7 +4434,7 @@ static void pvr2_hdw_quiescent_timeout(unsigned long data) | |||
4443 | hdw->state_decoder_quiescent = !0; | 4434 | hdw->state_decoder_quiescent = !0; |
4444 | trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); | 4435 | trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); |
4445 | hdw->state_stale = !0; | 4436 | hdw->state_stale = !0; |
4446 | queue_work(hdw->workqueue,&hdw->workpoll); | 4437 | schedule_work(&hdw->workpoll); |
4447 | } | 4438 | } |
4448 | 4439 | ||
4449 | 4440 | ||
@@ -4454,7 +4445,7 @@ static void pvr2_hdw_decoder_stabilization_timeout(unsigned long data) | |||
4454 | hdw->state_decoder_ready = !0; | 4445 | hdw->state_decoder_ready = !0; |
4455 | trace_stbit("state_decoder_ready", hdw->state_decoder_ready); | 4446 | trace_stbit("state_decoder_ready", hdw->state_decoder_ready); |
4456 | hdw->state_stale = !0; | 4447 | hdw->state_stale = !0; |
4457 | queue_work(hdw->workqueue, &hdw->workpoll); | 4448 | schedule_work(&hdw->workpoll); |
4458 | } | 4449 | } |
4459 | 4450 | ||
4460 | 4451 | ||
@@ -4465,7 +4456,7 @@ static void pvr2_hdw_encoder_wait_timeout(unsigned long data) | |||
4465 | hdw->state_encoder_waitok = !0; | 4456 | hdw->state_encoder_waitok = !0; |
4466 | trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); | 4457 | trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); |
4467 | hdw->state_stale = !0; | 4458 | hdw->state_stale = !0; |
4468 | queue_work(hdw->workqueue,&hdw->workpoll); | 4459 | schedule_work(&hdw->workpoll); |
4469 | } | 4460 | } |
4470 | 4461 | ||
4471 | 4462 | ||
@@ -4477,7 +4468,7 @@ static void pvr2_hdw_encoder_run_timeout(unsigned long data) | |||
4477 | hdw->state_encoder_runok = !0; | 4468 | hdw->state_encoder_runok = !0; |
4478 | trace_stbit("state_encoder_runok",hdw->state_encoder_runok); | 4469 | trace_stbit("state_encoder_runok",hdw->state_encoder_runok); |
4479 | hdw->state_stale = !0; | 4470 | hdw->state_stale = !0; |
4480 | queue_work(hdw->workqueue,&hdw->workpoll); | 4471 | schedule_work(&hdw->workpoll); |
4481 | } | 4472 | } |
4482 | } | 4473 | } |
4483 | 4474 | ||
@@ -4991,7 +4982,7 @@ static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw) | |||
4991 | if (hdw->state_stale) return; | 4982 | if (hdw->state_stale) return; |
4992 | hdw->state_stale = !0; | 4983 | hdw->state_stale = !0; |
4993 | trace_stbit("state_stale",hdw->state_stale); | 4984 | trace_stbit("state_stale",hdw->state_stale); |
4994 | queue_work(hdw->workqueue,&hdw->workpoll); | 4985 | schedule_work(&hdw->workpoll); |
4995 | } | 4986 | } |
4996 | 4987 | ||
4997 | 4988 | ||
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c index 14321d0a1833..6da5fb544817 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c | |||
@@ -596,7 +596,8 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) | |||
596 | case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */ | 596 | case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */ |
597 | init_data->ir_codes = RC_MAP_HAUPPAUGE; | 597 | init_data->ir_codes = RC_MAP_HAUPPAUGE; |
598 | init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; | 598 | init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; |
599 | init_data->type = RC_BIT_RC5; | 599 | init_data->type = RC_BIT_RC5 | RC_BIT_RC6_MCE | |
600 | RC_BIT_RC6_6A_32; | ||
600 | init_data->name = hdw->hdw_desc->description; | 601 | init_data->name = hdw->hdw_desc->description; |
601 | /* IR Receiver */ | 602 | /* IR Receiver */ |
602 | info.addr = 0x71; | 603 | info.addr = 0x71; |
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 81f788b7b242..2cc4d2b6f810 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | |||
@@ -719,64 +719,85 @@ static int pvr2_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap) | |||
719 | return ret; | 719 | return ret; |
720 | } | 720 | } |
721 | 721 | ||
722 | static int pvr2_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) | 722 | static int pvr2_g_selection(struct file *file, void *priv, |
723 | struct v4l2_selection *sel) | ||
723 | { | 724 | { |
724 | struct pvr2_v4l2_fh *fh = file->private_data; | 725 | struct pvr2_v4l2_fh *fh = file->private_data; |
725 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | 726 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
727 | struct v4l2_cropcap cap; | ||
726 | int val = 0; | 728 | int val = 0; |
727 | int ret; | 729 | int ret; |
728 | 730 | ||
729 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 731 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
730 | return -EINVAL; | 732 | return -EINVAL; |
731 | ret = pvr2_ctrl_get_value( | 733 | |
732 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val); | 734 | cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
733 | if (ret != 0) | 735 | |
734 | return -EINVAL; | 736 | switch (sel->target) { |
735 | crop->c.left = val; | 737 | case V4L2_SEL_TGT_CROP: |
736 | ret = pvr2_ctrl_get_value( | 738 | ret = pvr2_ctrl_get_value( |
737 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val); | 739 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val); |
738 | if (ret != 0) | 740 | if (ret != 0) |
739 | return -EINVAL; | 741 | return -EINVAL; |
740 | crop->c.top = val; | 742 | sel->r.left = val; |
741 | ret = pvr2_ctrl_get_value( | 743 | ret = pvr2_ctrl_get_value( |
742 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val); | 744 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val); |
743 | if (ret != 0) | 745 | if (ret != 0) |
744 | return -EINVAL; | 746 | return -EINVAL; |
745 | crop->c.width = val; | 747 | sel->r.top = val; |
746 | ret = pvr2_ctrl_get_value( | 748 | ret = pvr2_ctrl_get_value( |
747 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val); | 749 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val); |
748 | if (ret != 0) | 750 | if (ret != 0) |
751 | return -EINVAL; | ||
752 | sel->r.width = val; | ||
753 | ret = pvr2_ctrl_get_value( | ||
754 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val); | ||
755 | if (ret != 0) | ||
756 | return -EINVAL; | ||
757 | sel->r.height = val; | ||
758 | break; | ||
759 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
760 | ret = pvr2_hdw_get_cropcap(hdw, &cap); | ||
761 | sel->r = cap.defrect; | ||
762 | break; | ||
763 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
764 | ret = pvr2_hdw_get_cropcap(hdw, &cap); | ||
765 | sel->r = cap.bounds; | ||
766 | break; | ||
767 | default: | ||
749 | return -EINVAL; | 768 | return -EINVAL; |
750 | crop->c.height = val; | 769 | } |
751 | return 0; | 770 | return ret; |
752 | } | 771 | } |
753 | 772 | ||
754 | static int pvr2_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop) | 773 | static int pvr2_s_selection(struct file *file, void *priv, |
774 | struct v4l2_selection *sel) | ||
755 | { | 775 | { |
756 | struct pvr2_v4l2_fh *fh = file->private_data; | 776 | struct pvr2_v4l2_fh *fh = file->private_data; |
757 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | 777 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; |
758 | int ret; | 778 | int ret; |
759 | 779 | ||
760 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 780 | if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || |
781 | sel->target != V4L2_SEL_TGT_CROP) | ||
761 | return -EINVAL; | 782 | return -EINVAL; |
762 | ret = pvr2_ctrl_set_value( | 783 | ret = pvr2_ctrl_set_value( |
763 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), | 784 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), |
764 | crop->c.left); | 785 | sel->r.left); |
765 | if (ret != 0) | 786 | if (ret != 0) |
766 | return -EINVAL; | 787 | return -EINVAL; |
767 | ret = pvr2_ctrl_set_value( | 788 | ret = pvr2_ctrl_set_value( |
768 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), | 789 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), |
769 | crop->c.top); | 790 | sel->r.top); |
770 | if (ret != 0) | 791 | if (ret != 0) |
771 | return -EINVAL; | 792 | return -EINVAL; |
772 | ret = pvr2_ctrl_set_value( | 793 | ret = pvr2_ctrl_set_value( |
773 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), | 794 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), |
774 | crop->c.width); | 795 | sel->r.width); |
775 | if (ret != 0) | 796 | if (ret != 0) |
776 | return -EINVAL; | 797 | return -EINVAL; |
777 | ret = pvr2_ctrl_set_value( | 798 | ret = pvr2_ctrl_set_value( |
778 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), | 799 | pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), |
779 | crop->c.height); | 800 | sel->r.height); |
780 | if (ret != 0) | 801 | if (ret != 0) |
781 | return -EINVAL; | 802 | return -EINVAL; |
782 | return 0; | 803 | return 0; |
@@ -798,8 +819,8 @@ static const struct v4l2_ioctl_ops pvr2_ioctl_ops = { | |||
798 | .vidioc_enumaudio = pvr2_enumaudio, | 819 | .vidioc_enumaudio = pvr2_enumaudio, |
799 | .vidioc_enum_input = pvr2_enum_input, | 820 | .vidioc_enum_input = pvr2_enum_input, |
800 | .vidioc_cropcap = pvr2_cropcap, | 821 | .vidioc_cropcap = pvr2_cropcap, |
801 | .vidioc_s_crop = pvr2_s_crop, | 822 | .vidioc_s_selection = pvr2_s_selection, |
802 | .vidioc_g_crop = pvr2_g_crop, | 823 | .vidioc_g_selection = pvr2_g_selection, |
803 | .vidioc_g_input = pvr2_g_input, | 824 | .vidioc_g_input = pvr2_g_input, |
804 | .vidioc_s_input = pvr2_s_input, | 825 | .vidioc_s_input = pvr2_s_input, |
805 | .vidioc_g_frequency = pvr2_g_frequency, | 826 | .vidioc_g_frequency = pvr2_g_frequency, |
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index c4454c928776..ff657644b6b3 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c | |||
@@ -707,7 +707,7 @@ static void stop_streaming(struct vb2_queue *vq) | |||
707 | mutex_unlock(&pdev->v4l2_lock); | 707 | mutex_unlock(&pdev->v4l2_lock); |
708 | } | 708 | } |
709 | 709 | ||
710 | static struct vb2_ops pwc_vb_queue_ops = { | 710 | static const struct vb2_ops pwc_vb_queue_ops = { |
711 | .queue_setup = queue_setup, | 711 | .queue_setup = queue_setup, |
712 | .buf_init = buffer_init, | 712 | .buf_init = buffer_init, |
713 | .buf_prepare = buffer_prepare, | 713 | .buf_prepare = buffer_prepare, |
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 9458eb0ef66f..c3a0e87066eb 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c | |||
@@ -717,7 +717,7 @@ static void buffer_queue(struct vb2_buffer *vb) | |||
717 | static int start_streaming(struct vb2_queue *vq, unsigned int count); | 717 | static int start_streaming(struct vb2_queue *vq, unsigned int count); |
718 | static void stop_streaming(struct vb2_queue *vq); | 718 | static void stop_streaming(struct vb2_queue *vq); |
719 | 719 | ||
720 | static struct vb2_ops s2255_video_qops = { | 720 | static const struct vb2_ops s2255_video_qops = { |
721 | .queue_setup = queue_setup, | 721 | .queue_setup = queue_setup, |
722 | .buf_prepare = buffer_prepare, | 722 | .buf_prepare = buffer_prepare, |
723 | .buf_queue = buffer_queue, | 723 | .buf_queue = buffer_queue, |
diff --git a/drivers/media/usb/stk1160/stk1160-i2c.c b/drivers/media/usb/stk1160/stk1160-i2c.c index 850cf285ada8..3f2517be02bb 100644 --- a/drivers/media/usb/stk1160/stk1160-i2c.c +++ b/drivers/media/usb/stk1160/stk1160-i2c.c | |||
@@ -235,7 +235,7 @@ static u32 functionality(struct i2c_adapter *adap) | |||
235 | return I2C_FUNC_SMBUS_EMUL; | 235 | return I2C_FUNC_SMBUS_EMUL; |
236 | } | 236 | } |
237 | 237 | ||
238 | static struct i2c_algorithm algo = { | 238 | static const struct i2c_algorithm algo = { |
239 | .master_xfer = stk1160_i2c_xfer, | 239 | .master_xfer = stk1160_i2c_xfer, |
240 | .functionality = functionality, | 240 | .functionality = functionality, |
241 | }; | 241 | }; |
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 5fab3bee8c74..a005d262392a 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c | |||
@@ -742,7 +742,7 @@ static void stop_streaming(struct vb2_queue *vq) | |||
742 | stk1160_stop_streaming(dev); | 742 | stk1160_stop_streaming(dev); |
743 | } | 743 | } |
744 | 744 | ||
745 | static struct vb2_ops stk1160_video_qops = { | 745 | static const struct vb2_ops stk1160_video_qops = { |
746 | .queue_setup = queue_setup, | 746 | .queue_setup = queue_setup, |
747 | .buf_queue = buffer_queue, | 747 | .buf_queue = buffer_queue, |
748 | .start_streaming = start_streaming, | 748 | .start_streaming = start_streaming, |
diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c index e21c7aacecb6..f16fbd1f9f51 100644 --- a/drivers/media/usb/tm6000/tm6000-alsa.c +++ b/drivers/media/usb/tm6000/tm6000-alsa.c | |||
@@ -388,7 +388,7 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, | |||
388 | /* | 388 | /* |
389 | * operators | 389 | * operators |
390 | */ | 390 | */ |
391 | static struct snd_pcm_ops snd_tm6000_pcm_ops = { | 391 | static const struct snd_pcm_ops snd_tm6000_pcm_ops = { |
392 | .open = snd_tm6000_pcm_open, | 392 | .open = snd_tm6000_pcm_open, |
393 | .close = snd_tm6000_close, | 393 | .close = snd_tm6000_close, |
394 | .ioctl = snd_pcm_lib_ioctl, | 394 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 4e36e24cb3a6..4e7671a3a1e4 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c | |||
@@ -206,7 +206,7 @@ static void ttusb_dec_set_model(struct ttusb_dec *dec, | |||
206 | 206 | ||
207 | static void ttusb_dec_handle_irq( struct urb *urb) | 207 | static void ttusb_dec_handle_irq( struct urb *urb) |
208 | { | 208 | { |
209 | struct ttusb_dec * dec = urb->context; | 209 | struct ttusb_dec *dec = urb->context; |
210 | char *buffer = dec->irq_buffer; | 210 | char *buffer = dec->irq_buffer; |
211 | int retval; | 211 | int retval; |
212 | 212 | ||
@@ -227,25 +227,31 @@ static void ttusb_dec_handle_irq( struct urb *urb) | |||
227 | goto exit; | 227 | goto exit; |
228 | } | 228 | } |
229 | 229 | ||
230 | if( (buffer[0] == 0x1) && (buffer[2] == 0x15) ) { | 230 | if ((buffer[0] == 0x1) && (buffer[2] == 0x15)) { |
231 | /* IR - Event */ | 231 | /* |
232 | /* this is an fact a bit too simple implementation; | 232 | * IR - Event |
233 | * | ||
234 | * this is an fact a bit too simple implementation; | ||
233 | * the box also reports a keyrepeat signal | 235 | * the box also reports a keyrepeat signal |
234 | * (with buffer[3] == 0x40) in an intervall of ~100ms. | 236 | * (with buffer[3] == 0x40) in an intervall of ~100ms. |
235 | * But to handle this correctly we had to imlemenent some | 237 | * But to handle this correctly we had to imlemenent some |
236 | * kind of timer which signals a 'key up' event if no | 238 | * kind of timer which signals a 'key up' event if no |
237 | * keyrepeat signal is received for lets say 200ms. | 239 | * keyrepeat signal is received for lets say 200ms. |
238 | * this should/could be added later ... | 240 | * this should/could be added later ... |
239 | * for now lets report each signal as a key down and up*/ | 241 | * for now lets report each signal as a key down and up |
240 | dprintk("%s:rc signal:%d\n", __func__, buffer[4]); | 242 | */ |
241 | input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1); | 243 | if (buffer[4] - 1 < ARRAY_SIZE(rc_keys)) { |
242 | input_sync(dec->rc_input_dev); | 244 | dprintk("%s:rc signal:%d\n", __func__, buffer[4]); |
243 | input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0); | 245 | input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1); |
244 | input_sync(dec->rc_input_dev); | 246 | input_sync(dec->rc_input_dev); |
247 | input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0); | ||
248 | input_sync(dec->rc_input_dev); | ||
249 | } | ||
245 | } | 250 | } |
246 | 251 | ||
247 | exit: retval = usb_submit_urb(urb, GFP_ATOMIC); | 252 | exit: |
248 | if(retval) | 253 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
254 | if (retval) | ||
249 | printk("%s - usb_commit_urb failed with result: %d\n", | 255 | printk("%s - usb_commit_urb failed with result: %d\n", |
250 | __func__, retval); | 256 | __func__, retval); |
251 | } | 257 | } |
diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c index 1965ff1b1f12..9db31db7d9ac 100644 --- a/drivers/media/usb/usbtv/usbtv-audio.c +++ b/drivers/media/usb/usbtv/usbtv-audio.c | |||
@@ -332,7 +332,7 @@ static snd_pcm_uframes_t snd_usbtv_pointer(struct snd_pcm_substream *substream) | |||
332 | return chip->snd_buffer_pos; | 332 | return chip->snd_buffer_pos; |
333 | } | 333 | } |
334 | 334 | ||
335 | static struct snd_pcm_ops snd_usbtv_pcm_ops = { | 335 | static const struct snd_pcm_ops snd_usbtv_pcm_ops = { |
336 | .open = snd_usbtv_pcm_open, | 336 | .open = snd_usbtv_pcm_open, |
337 | .close = snd_usbtv_pcm_close, | 337 | .close = snd_usbtv_pcm_close, |
338 | .ioctl = snd_pcm_lib_ioctl, | 338 | .ioctl = snd_pcm_lib_ioctl, |
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 2a089756c988..6cbe4a245c9f 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c | |||
@@ -689,7 +689,7 @@ static void usbtv_stop_streaming(struct vb2_queue *vq) | |||
689 | usbtv_stop(usbtv); | 689 | usbtv_stop(usbtv); |
690 | } | 690 | } |
691 | 691 | ||
692 | static struct vb2_ops usbtv_vb2_ops = { | 692 | static const struct vb2_ops usbtv_vb2_ops = { |
693 | .queue_setup = usbtv_queue_setup, | 693 | .queue_setup = usbtv_queue_setup, |
694 | .buf_queue = usbtv_buf_queue, | 694 | .buf_queue = usbtv_buf_queue, |
695 | .start_streaming = usbtv_start_streaming, | 695 | .start_streaming = usbtv_start_streaming, |
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 773fefb52d7a..77edd206d345 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c | |||
@@ -177,7 +177,7 @@ static void uvc_stop_streaming(struct vb2_queue *vq) | |||
177 | spin_unlock_irqrestore(&queue->irqlock, flags); | 177 | spin_unlock_irqrestore(&queue->irqlock, flags); |
178 | } | 178 | } |
179 | 179 | ||
180 | static struct vb2_ops uvc_queue_qops = { | 180 | static const struct vb2_ops uvc_queue_qops = { |
181 | .queue_setup = uvc_queue_setup, | 181 | .queue_setup = uvc_queue_setup, |
182 | .buf_prepare = uvc_buffer_prepare, | 182 | .buf_prepare = uvc_buffer_prepare, |
183 | .buf_queue = uvc_buffer_queue, | 183 | .buf_queue = uvc_buffer_queue, |
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index a4b224d92572..5bada202b2d3 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c | |||
@@ -119,13 +119,6 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier, | |||
119 | return ret; | 119 | return ret; |
120 | } | 120 | } |
121 | 121 | ||
122 | ret = v4l2_subdev_call(sd, core, registered_async); | ||
123 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
124 | if (notifier->unbind) | ||
125 | notifier->unbind(notifier, sd, asd); | ||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | if (list_empty(¬ifier->waiting) && notifier->complete) | 122 | if (list_empty(¬ifier->waiting) && notifier->complete) |
130 | return notifier->complete(notifier); | 123 | return notifier->complete(notifier); |
131 | 124 | ||
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 5b808500e7e7..57cfe26a393f 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c | |||
@@ -291,7 +291,7 @@ struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, | |||
291 | error: | 291 | error: |
292 | /* If we have a client but no subdev, then something went wrong and | 292 | /* If we have a client but no subdev, then something went wrong and |
293 | we must unregister the client. */ | 293 | we must unregister the client. */ |
294 | if (spi && sd == NULL) | 294 | if (!sd) |
295 | spi_unregister_device(spi); | 295 | spi_unregister_device(spi); |
296 | 296 | ||
297 | return sd; | 297 | return sd; |
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index f7abfad9ad23..adc2147fcff7 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c | |||
@@ -361,6 +361,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id) | |||
361 | "Scalable Baseline", | 361 | "Scalable Baseline", |
362 | "Scalable High", | 362 | "Scalable High", |
363 | "Scalable High Intra", | 363 | "Scalable High Intra", |
364 | "Stereo High", | ||
364 | "Multiview High", | 365 | "Multiview High", |
365 | NULL, | 366 | NULL, |
366 | }; | 367 | }; |
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index e6da353b39bc..8be561ab2615 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c | |||
@@ -527,6 +527,7 @@ static void determine_valid_ioctls(struct video_device *vdev) | |||
527 | bool is_vbi = vdev->vfl_type == VFL_TYPE_VBI; | 527 | bool is_vbi = vdev->vfl_type == VFL_TYPE_VBI; |
528 | bool is_radio = vdev->vfl_type == VFL_TYPE_RADIO; | 528 | bool is_radio = vdev->vfl_type == VFL_TYPE_RADIO; |
529 | bool is_sdr = vdev->vfl_type == VFL_TYPE_SDR; | 529 | bool is_sdr = vdev->vfl_type == VFL_TYPE_SDR; |
530 | bool is_tch = vdev->vfl_type == VFL_TYPE_TOUCH; | ||
530 | bool is_rx = vdev->vfl_dir != VFL_DIR_TX; | 531 | bool is_rx = vdev->vfl_dir != VFL_DIR_TX; |
531 | bool is_tx = vdev->vfl_dir != VFL_DIR_RX; | 532 | bool is_tx = vdev->vfl_dir != VFL_DIR_RX; |
532 | 533 | ||
@@ -573,7 +574,7 @@ static void determine_valid_ioctls(struct video_device *vdev) | |||
573 | if (ops->vidioc_enum_freq_bands || ops->vidioc_g_tuner || ops->vidioc_g_modulator) | 574 | if (ops->vidioc_enum_freq_bands || ops->vidioc_g_tuner || ops->vidioc_g_modulator) |
574 | set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls); | 575 | set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls); |
575 | 576 | ||
576 | if (is_vid) { | 577 | if (is_vid || is_tch) { |
577 | /* video specific ioctls */ | 578 | /* video specific ioctls */ |
578 | if ((is_rx && (ops->vidioc_enum_fmt_vid_cap || | 579 | if ((is_rx && (ops->vidioc_enum_fmt_vid_cap || |
579 | ops->vidioc_enum_fmt_vid_cap_mplane || | 580 | ops->vidioc_enum_fmt_vid_cap_mplane || |
@@ -662,7 +663,7 @@ static void determine_valid_ioctls(struct video_device *vdev) | |||
662 | set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); | 663 | set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); |
663 | } | 664 | } |
664 | 665 | ||
665 | if (is_vid || is_vbi || is_sdr) { | 666 | if (is_vid || is_vbi || is_sdr || is_tch) { |
666 | /* ioctls valid for video, vbi or sdr */ | 667 | /* ioctls valid for video, vbi or sdr */ |
667 | SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs); | 668 | SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs); |
668 | SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf); | 669 | SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf); |
@@ -675,7 +676,7 @@ static void determine_valid_ioctls(struct video_device *vdev) | |||
675 | SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff); | 676 | SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff); |
676 | } | 677 | } |
677 | 678 | ||
678 | if (is_vid || is_vbi) { | 679 | if (is_vid || is_vbi || is_tch) { |
679 | /* ioctls valid for video or vbi */ | 680 | /* ioctls valid for video or vbi */ |
680 | if (ops->vidioc_s_std) | 681 | if (ops->vidioc_s_std) |
681 | set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls); | 682 | set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls); |
@@ -751,6 +752,10 @@ static int video_register_media_controller(struct video_device *vdev, int type) | |||
751 | intf_type = MEDIA_INTF_T_V4L_SWRADIO; | 752 | intf_type = MEDIA_INTF_T_V4L_SWRADIO; |
752 | vdev->entity.function = MEDIA_ENT_F_IO_SWRADIO; | 753 | vdev->entity.function = MEDIA_ENT_F_IO_SWRADIO; |
753 | break; | 754 | break; |
755 | case VFL_TYPE_TOUCH: | ||
756 | intf_type = MEDIA_INTF_T_V4L_TOUCH; | ||
757 | vdev->entity.function = MEDIA_ENT_F_IO_V4L; | ||
758 | break; | ||
754 | case VFL_TYPE_RADIO: | 759 | case VFL_TYPE_RADIO: |
755 | intf_type = MEDIA_INTF_T_V4L_RADIO; | 760 | intf_type = MEDIA_INTF_T_V4L_RADIO; |
756 | /* | 761 | /* |
@@ -854,6 +859,9 @@ int __video_register_device(struct video_device *vdev, int type, int nr, | |||
854 | /* Use device name 'swradio' because 'sdr' was already taken. */ | 859 | /* Use device name 'swradio' because 'sdr' was already taken. */ |
855 | name_base = "swradio"; | 860 | name_base = "swradio"; |
856 | break; | 861 | break; |
862 | case VFL_TYPE_TOUCH: | ||
863 | name_base = "v4l-touch"; | ||
864 | break; | ||
857 | default: | 865 | default: |
858 | printk(KERN_ERR "%s called with unknown type: %d\n", | 866 | printk(KERN_ERR "%s called with unknown type: %d\n", |
859 | __func__, type); | 867 | __func__, type); |
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index 06fa5f1b2cff..62bbed76dbbc 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c | |||
@@ -160,12 +160,9 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, | |||
160 | int err; | 160 | int err; |
161 | 161 | ||
162 | /* Check for valid input */ | 162 | /* Check for valid input */ |
163 | if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) | 163 | if (!v4l2_dev || !sd || sd->v4l2_dev || !sd->name[0]) |
164 | return -EINVAL; | 164 | return -EINVAL; |
165 | 165 | ||
166 | /* Warn if we apparently re-register a subdev */ | ||
167 | WARN_ON(sd->v4l2_dev != NULL); | ||
168 | |||
169 | /* | 166 | /* |
170 | * The reason to acquire the module here is to avoid unloading | 167 | * The reason to acquire the module here is to avoid unloading |
171 | * a module of sub-device which is registered to a media | 168 | * a module of sub-device which is registered to a media |
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 889de0a32152..730a7c392c1d 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c | |||
@@ -306,7 +306,7 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, | |||
306 | (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-", | 306 | (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-", |
307 | bt->il_vsync, bt->il_vbackporch); | 307 | bt->il_vsync, bt->il_vbackporch); |
308 | pr_info("%s: pixelclock: %llu\n", dev_prefix, bt->pixelclock); | 308 | pr_info("%s: pixelclock: %llu\n", dev_prefix, bt->pixelclock); |
309 | pr_info("%s: flags (0x%x):%s%s%s%s%s%s\n", dev_prefix, bt->flags, | 309 | pr_info("%s: flags (0x%x):%s%s%s%s%s%s%s\n", dev_prefix, bt->flags, |
310 | (bt->flags & V4L2_DV_FL_REDUCED_BLANKING) ? | 310 | (bt->flags & V4L2_DV_FL_REDUCED_BLANKING) ? |
311 | " REDUCED_BLANKING" : "", | 311 | " REDUCED_BLANKING" : "", |
312 | ((bt->flags & V4L2_DV_FL_REDUCED_BLANKING) && | 312 | ((bt->flags & V4L2_DV_FL_REDUCED_BLANKING) && |
@@ -318,12 +318,15 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, | |||
318 | (bt->flags & V4L2_DV_FL_HALF_LINE) ? | 318 | (bt->flags & V4L2_DV_FL_HALF_LINE) ? |
319 | " HALF_LINE" : "", | 319 | " HALF_LINE" : "", |
320 | (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) ? | 320 | (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) ? |
321 | " CE_VIDEO" : ""); | 321 | " CE_VIDEO" : "", |
322 | pr_info("%s: standards (0x%x):%s%s%s%s\n", dev_prefix, bt->standards, | 322 | (bt->flags & V4L2_DV_FL_FIRST_FIELD_EXTRA_LINE) ? |
323 | " FIRST_FIELD_EXTRA_LINE" : ""); | ||
324 | pr_info("%s: standards (0x%x):%s%s%s%s%s\n", dev_prefix, bt->standards, | ||
323 | (bt->standards & V4L2_DV_BT_STD_CEA861) ? " CEA" : "", | 325 | (bt->standards & V4L2_DV_BT_STD_CEA861) ? " CEA" : "", |
324 | (bt->standards & V4L2_DV_BT_STD_DMT) ? " DMT" : "", | 326 | (bt->standards & V4L2_DV_BT_STD_DMT) ? " DMT" : "", |
325 | (bt->standards & V4L2_DV_BT_STD_CVT) ? " CVT" : "", | 327 | (bt->standards & V4L2_DV_BT_STD_CVT) ? " CVT" : "", |
326 | (bt->standards & V4L2_DV_BT_STD_GTF) ? " GTF" : ""); | 328 | (bt->standards & V4L2_DV_BT_STD_GTF) ? " GTF" : "", |
329 | (bt->standards & V4L2_DV_BT_STD_SDI) ? " SDI" : ""); | ||
327 | } | 330 | } |
328 | EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); | 331 | EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); |
329 | 332 | ||
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 51a0fa144392..c52d94c018bb 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c | |||
@@ -924,6 +924,7 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type) | |||
924 | bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; | 924 | bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; |
925 | bool is_vbi = vfd->vfl_type == VFL_TYPE_VBI; | 925 | bool is_vbi = vfd->vfl_type == VFL_TYPE_VBI; |
926 | bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; | 926 | bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; |
927 | bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH; | ||
927 | bool is_rx = vfd->vfl_dir != VFL_DIR_TX; | 928 | bool is_rx = vfd->vfl_dir != VFL_DIR_TX; |
928 | bool is_tx = vfd->vfl_dir != VFL_DIR_RX; | 929 | bool is_tx = vfd->vfl_dir != VFL_DIR_RX; |
929 | 930 | ||
@@ -932,7 +933,7 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type) | |||
932 | 933 | ||
933 | switch (type) { | 934 | switch (type) { |
934 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 935 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
935 | if (is_vid && is_rx && | 936 | if ((is_vid || is_tch) && is_rx && |
936 | (ops->vidioc_g_fmt_vid_cap || ops->vidioc_g_fmt_vid_cap_mplane)) | 937 | (ops->vidioc_g_fmt_vid_cap || ops->vidioc_g_fmt_vid_cap_mplane)) |
937 | return 0; | 938 | return 0; |
938 | break; | 939 | break; |
@@ -1243,6 +1244,10 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) | |||
1243 | case V4L2_SDR_FMT_CS8: descr = "Complex S8"; break; | 1244 | case V4L2_SDR_FMT_CS8: descr = "Complex S8"; break; |
1244 | case V4L2_SDR_FMT_CS14LE: descr = "Complex S14LE"; break; | 1245 | case V4L2_SDR_FMT_CS14LE: descr = "Complex S14LE"; break; |
1245 | case V4L2_SDR_FMT_RU12LE: descr = "Real U12LE"; break; | 1246 | case V4L2_SDR_FMT_RU12LE: descr = "Real U12LE"; break; |
1247 | case V4L2_TCH_FMT_DELTA_TD16: descr = "16-bit signed deltas"; break; | ||
1248 | case V4L2_TCH_FMT_DELTA_TD08: descr = "8-bit signed deltas"; break; | ||
1249 | case V4L2_TCH_FMT_TU16: descr = "16-bit unsigned touch data"; break; | ||
1250 | case V4L2_TCH_FMT_TU08: descr = "8-bit unsigned touch data"; break; | ||
1246 | 1251 | ||
1247 | default: | 1252 | default: |
1248 | /* Compressed formats */ | 1253 | /* Compressed formats */ |
@@ -1309,13 +1314,14 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, | |||
1309 | struct video_device *vfd = video_devdata(file); | 1314 | struct video_device *vfd = video_devdata(file); |
1310 | bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; | 1315 | bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; |
1311 | bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; | 1316 | bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; |
1317 | bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH; | ||
1312 | bool is_rx = vfd->vfl_dir != VFL_DIR_TX; | 1318 | bool is_rx = vfd->vfl_dir != VFL_DIR_TX; |
1313 | bool is_tx = vfd->vfl_dir != VFL_DIR_RX; | 1319 | bool is_tx = vfd->vfl_dir != VFL_DIR_RX; |
1314 | int ret = -EINVAL; | 1320 | int ret = -EINVAL; |
1315 | 1321 | ||
1316 | switch (p->type) { | 1322 | switch (p->type) { |
1317 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1323 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
1318 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_vid_cap)) | 1324 | if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_enum_fmt_vid_cap)) |
1319 | break; | 1325 | break; |
1320 | ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg); | 1326 | ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg); |
1321 | break; | 1327 | break; |
@@ -1362,6 +1368,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, | |||
1362 | struct video_device *vfd = video_devdata(file); | 1368 | struct video_device *vfd = video_devdata(file); |
1363 | bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; | 1369 | bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; |
1364 | bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; | 1370 | bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; |
1371 | bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH; | ||
1365 | bool is_rx = vfd->vfl_dir != VFL_DIR_TX; | 1372 | bool is_rx = vfd->vfl_dir != VFL_DIR_TX; |
1366 | bool is_tx = vfd->vfl_dir != VFL_DIR_RX; | 1373 | bool is_tx = vfd->vfl_dir != VFL_DIR_RX; |
1367 | int ret; | 1374 | int ret; |
@@ -1392,7 +1399,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, | |||
1392 | 1399 | ||
1393 | switch (p->type) { | 1400 | switch (p->type) { |
1394 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1401 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
1395 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_cap)) | 1402 | if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_g_fmt_vid_cap)) |
1396 | break; | 1403 | break; |
1397 | p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; | 1404 | p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; |
1398 | ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg); | 1405 | ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg); |
@@ -1451,6 +1458,21 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, | |||
1451 | return -EINVAL; | 1458 | return -EINVAL; |
1452 | } | 1459 | } |
1453 | 1460 | ||
1461 | static void v4l_pix_format_touch(struct v4l2_pix_format *p) | ||
1462 | { | ||
1463 | /* | ||
1464 | * The v4l2_pix_format structure contains fields that make no sense for | ||
1465 | * touch. Set them to default values in this case. | ||
1466 | */ | ||
1467 | |||
1468 | p->field = V4L2_FIELD_NONE; | ||
1469 | p->colorspace = V4L2_COLORSPACE_RAW; | ||
1470 | p->flags = 0; | ||
1471 | p->ycbcr_enc = 0; | ||
1472 | p->quantization = 0; | ||
1473 | p->xfer_func = 0; | ||
1474 | } | ||
1475 | |||
1454 | static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, | 1476 | static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, |
1455 | struct file *file, void *fh, void *arg) | 1477 | struct file *file, void *fh, void *arg) |
1456 | { | 1478 | { |
@@ -1458,6 +1480,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, | |||
1458 | struct video_device *vfd = video_devdata(file); | 1480 | struct video_device *vfd = video_devdata(file); |
1459 | bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; | 1481 | bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; |
1460 | bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; | 1482 | bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; |
1483 | bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH; | ||
1461 | bool is_rx = vfd->vfl_dir != VFL_DIR_TX; | 1484 | bool is_rx = vfd->vfl_dir != VFL_DIR_TX; |
1462 | bool is_tx = vfd->vfl_dir != VFL_DIR_RX; | 1485 | bool is_tx = vfd->vfl_dir != VFL_DIR_RX; |
1463 | int ret; | 1486 | int ret; |
@@ -1469,17 +1492,19 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, | |||
1469 | 1492 | ||
1470 | switch (p->type) { | 1493 | switch (p->type) { |
1471 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1494 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
1472 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_cap)) | 1495 | if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_s_fmt_vid_cap)) |
1473 | break; | 1496 | break; |
1474 | CLEAR_AFTER_FIELD(p, fmt.pix); | 1497 | CLEAR_AFTER_FIELD(p, fmt.pix); |
1475 | ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg); | 1498 | ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg); |
1476 | /* just in case the driver zeroed it again */ | 1499 | /* just in case the driver zeroed it again */ |
1477 | p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; | 1500 | p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; |
1501 | if (is_tch) | ||
1502 | v4l_pix_format_touch(&p->fmt.pix); | ||
1478 | return ret; | 1503 | return ret; |
1479 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | 1504 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: |
1480 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_cap_mplane)) | 1505 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_cap_mplane)) |
1481 | break; | 1506 | break; |
1482 | CLEAR_AFTER_FIELD(p, fmt.pix_mp); | 1507 | CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); |
1483 | return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg); | 1508 | return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg); |
1484 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 1509 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
1485 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_overlay)) | 1510 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_overlay)) |
@@ -1507,7 +1532,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, | |||
1507 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | 1532 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: |
1508 | if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_mplane)) | 1533 | if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_mplane)) |
1509 | break; | 1534 | break; |
1510 | CLEAR_AFTER_FIELD(p, fmt.pix_mp); | 1535 | CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); |
1511 | return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg); | 1536 | return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg); |
1512 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 1537 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
1513 | if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_overlay)) | 1538 | if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_overlay)) |
@@ -1545,6 +1570,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, | |||
1545 | struct video_device *vfd = video_devdata(file); | 1570 | struct video_device *vfd = video_devdata(file); |
1546 | bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; | 1571 | bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; |
1547 | bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; | 1572 | bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; |
1573 | bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH; | ||
1548 | bool is_rx = vfd->vfl_dir != VFL_DIR_TX; | 1574 | bool is_rx = vfd->vfl_dir != VFL_DIR_TX; |
1549 | bool is_tx = vfd->vfl_dir != VFL_DIR_RX; | 1575 | bool is_tx = vfd->vfl_dir != VFL_DIR_RX; |
1550 | int ret; | 1576 | int ret; |
@@ -1553,7 +1579,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, | |||
1553 | 1579 | ||
1554 | switch (p->type) { | 1580 | switch (p->type) { |
1555 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1581 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
1556 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_cap)) | 1582 | if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_try_fmt_vid_cap)) |
1557 | break; | 1583 | break; |
1558 | CLEAR_AFTER_FIELD(p, fmt.pix); | 1584 | CLEAR_AFTER_FIELD(p, fmt.pix); |
1559 | ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg); | 1585 | ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg); |
@@ -1563,7 +1589,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, | |||
1563 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | 1589 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: |
1564 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_cap_mplane)) | 1590 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_cap_mplane)) |
1565 | break; | 1591 | break; |
1566 | CLEAR_AFTER_FIELD(p, fmt.pix_mp); | 1592 | CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); |
1567 | return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg); | 1593 | return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg); |
1568 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 1594 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
1569 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_overlay)) | 1595 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_overlay)) |
@@ -1591,7 +1617,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, | |||
1591 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | 1617 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: |
1592 | if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out_mplane)) | 1618 | if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out_mplane)) |
1593 | break; | 1619 | break; |
1594 | CLEAR_AFTER_FIELD(p, fmt.pix_mp); | 1620 | CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); |
1595 | return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg); | 1621 | return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg); |
1596 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 1622 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
1597 | if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out_overlay)) | 1623 | if (unlikely(!is_tx || !is_vid || !ops->vidioc_try_fmt_vid_out_overlay)) |
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 61d56c940f80..6bc27e7b2a33 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c | |||
@@ -76,9 +76,6 @@ static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx, | |||
76 | return &m2m_ctx->cap_q_ctx; | 76 | return &m2m_ctx->cap_q_ctx; |
77 | } | 77 | } |
78 | 78 | ||
79 | /** | ||
80 | * v4l2_m2m_get_vq() - return vb2_queue for the given type | ||
81 | */ | ||
82 | struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx, | 79 | struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx, |
83 | enum v4l2_buf_type type) | 80 | enum v4l2_buf_type type) |
84 | { | 81 | { |
@@ -92,9 +89,6 @@ struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx, | |||
92 | } | 89 | } |
93 | EXPORT_SYMBOL(v4l2_m2m_get_vq); | 90 | EXPORT_SYMBOL(v4l2_m2m_get_vq); |
94 | 91 | ||
95 | /** | ||
96 | * v4l2_m2m_next_buf() - return next buffer from the list of ready buffers | ||
97 | */ | ||
98 | void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx) | 92 | void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx) |
99 | { | 93 | { |
100 | struct v4l2_m2m_buffer *b; | 94 | struct v4l2_m2m_buffer *b; |
@@ -113,10 +107,6 @@ void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx) | |||
113 | } | 107 | } |
114 | EXPORT_SYMBOL_GPL(v4l2_m2m_next_buf); | 108 | EXPORT_SYMBOL_GPL(v4l2_m2m_next_buf); |
115 | 109 | ||
116 | /** | ||
117 | * v4l2_m2m_buf_remove() - take off a buffer from the list of ready buffers and | ||
118 | * return it | ||
119 | */ | ||
120 | void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx) | 110 | void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx) |
121 | { | 111 | { |
122 | struct v4l2_m2m_buffer *b; | 112 | struct v4l2_m2m_buffer *b; |
@@ -140,10 +130,6 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_buf_remove); | |||
140 | * Scheduling handlers | 130 | * Scheduling handlers |
141 | */ | 131 | */ |
142 | 132 | ||
143 | /** | ||
144 | * v4l2_m2m_get_curr_priv() - return driver private data for the currently | ||
145 | * running instance or NULL if no instance is running | ||
146 | */ | ||
147 | void *v4l2_m2m_get_curr_priv(struct v4l2_m2m_dev *m2m_dev) | 133 | void *v4l2_m2m_get_curr_priv(struct v4l2_m2m_dev *m2m_dev) |
148 | { | 134 | { |
149 | unsigned long flags; | 135 | unsigned long flags; |
@@ -188,26 +174,6 @@ static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev) | |||
188 | m2m_dev->m2m_ops->device_run(m2m_dev->curr_ctx->priv); | 174 | m2m_dev->m2m_ops->device_run(m2m_dev->curr_ctx->priv); |
189 | } | 175 | } |
190 | 176 | ||
191 | /** | ||
192 | * v4l2_m2m_try_schedule() - check whether an instance is ready to be added to | ||
193 | * the pending job queue and add it if so. | ||
194 | * @m2m_ctx: m2m context assigned to the instance to be checked | ||
195 | * | ||
196 | * There are three basic requirements an instance has to meet to be able to run: | ||
197 | * 1) at least one source buffer has to be queued, | ||
198 | * 2) at least one destination buffer has to be queued, | ||
199 | * 3) streaming has to be on. | ||
200 | * | ||
201 | * If a queue is buffered (for example a decoder hardware ringbuffer that has | ||
202 | * to be drained before doing streamoff), allow scheduling without v4l2 buffers | ||
203 | * on that queue. | ||
204 | * | ||
205 | * There may also be additional, custom requirements. In such case the driver | ||
206 | * should supply a custom callback (job_ready in v4l2_m2m_ops) that should | ||
207 | * return 1 if the instance is ready. | ||
208 | * An example of the above could be an instance that requires more than one | ||
209 | * src/dst buffer per transaction. | ||
210 | */ | ||
211 | void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx) | 177 | void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx) |
212 | { | 178 | { |
213 | struct v4l2_m2m_dev *m2m_dev; | 179 | struct v4l2_m2m_dev *m2m_dev; |
@@ -311,18 +277,6 @@ static void v4l2_m2m_cancel_job(struct v4l2_m2m_ctx *m2m_ctx) | |||
311 | } | 277 | } |
312 | } | 278 | } |
313 | 279 | ||
314 | /** | ||
315 | * v4l2_m2m_job_finish() - inform the framework that a job has been finished | ||
316 | * and have it clean up | ||
317 | * | ||
318 | * Called by a driver to yield back the device after it has finished with it. | ||
319 | * Should be called as soon as possible after reaching a state which allows | ||
320 | * other instances to take control of the device. | ||
321 | * | ||
322 | * This function has to be called only after device_run() callback has been | ||
323 | * called on the driver. To prevent recursion, it should not be called directly | ||
324 | * from the device_run() callback though. | ||
325 | */ | ||
326 | void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, | 280 | void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, |
327 | struct v4l2_m2m_ctx *m2m_ctx) | 281 | struct v4l2_m2m_ctx *m2m_ctx) |
328 | { | 282 | { |
@@ -350,9 +304,6 @@ void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, | |||
350 | } | 304 | } |
351 | EXPORT_SYMBOL(v4l2_m2m_job_finish); | 305 | EXPORT_SYMBOL(v4l2_m2m_job_finish); |
352 | 306 | ||
353 | /** | ||
354 | * v4l2_m2m_reqbufs() - multi-queue-aware REQBUFS multiplexer | ||
355 | */ | ||
356 | int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | 307 | int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, |
357 | struct v4l2_requestbuffers *reqbufs) | 308 | struct v4l2_requestbuffers *reqbufs) |
358 | { | 309 | { |
@@ -370,11 +321,6 @@ int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |||
370 | } | 321 | } |
371 | EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs); | 322 | EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs); |
372 | 323 | ||
373 | /** | ||
374 | * v4l2_m2m_querybuf() - multi-queue-aware QUERYBUF multiplexer | ||
375 | * | ||
376 | * See v4l2_m2m_mmap() documentation for details. | ||
377 | */ | ||
378 | int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | 324 | int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, |
379 | struct v4l2_buffer *buf) | 325 | struct v4l2_buffer *buf) |
380 | { | 326 | { |
@@ -400,10 +346,6 @@ int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |||
400 | } | 346 | } |
401 | EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf); | 347 | EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf); |
402 | 348 | ||
403 | /** | ||
404 | * v4l2_m2m_qbuf() - enqueue a source or destination buffer, depending on | ||
405 | * the type | ||
406 | */ | ||
407 | int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | 349 | int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, |
408 | struct v4l2_buffer *buf) | 350 | struct v4l2_buffer *buf) |
409 | { | 351 | { |
@@ -419,10 +361,6 @@ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |||
419 | } | 361 | } |
420 | EXPORT_SYMBOL_GPL(v4l2_m2m_qbuf); | 362 | EXPORT_SYMBOL_GPL(v4l2_m2m_qbuf); |
421 | 363 | ||
422 | /** | ||
423 | * v4l2_m2m_dqbuf() - dequeue a source or destination buffer, depending on | ||
424 | * the type | ||
425 | */ | ||
426 | int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | 364 | int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, |
427 | struct v4l2_buffer *buf) | 365 | struct v4l2_buffer *buf) |
428 | { | 366 | { |
@@ -433,10 +371,6 @@ int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |||
433 | } | 371 | } |
434 | EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf); | 372 | EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf); |
435 | 373 | ||
436 | /** | ||
437 | * v4l2_m2m_prepare_buf() - prepare a source or destination buffer, depending on | ||
438 | * the type | ||
439 | */ | ||
440 | int v4l2_m2m_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | 374 | int v4l2_m2m_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, |
441 | struct v4l2_buffer *buf) | 375 | struct v4l2_buffer *buf) |
442 | { | 376 | { |
@@ -452,10 +386,6 @@ int v4l2_m2m_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |||
452 | } | 386 | } |
453 | EXPORT_SYMBOL_GPL(v4l2_m2m_prepare_buf); | 387 | EXPORT_SYMBOL_GPL(v4l2_m2m_prepare_buf); |
454 | 388 | ||
455 | /** | ||
456 | * v4l2_m2m_create_bufs() - create a source or destination buffer, depending | ||
457 | * on the type | ||
458 | */ | ||
459 | int v4l2_m2m_create_bufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | 389 | int v4l2_m2m_create_bufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, |
460 | struct v4l2_create_buffers *create) | 390 | struct v4l2_create_buffers *create) |
461 | { | 391 | { |
@@ -466,10 +396,6 @@ int v4l2_m2m_create_bufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |||
466 | } | 396 | } |
467 | EXPORT_SYMBOL_GPL(v4l2_m2m_create_bufs); | 397 | EXPORT_SYMBOL_GPL(v4l2_m2m_create_bufs); |
468 | 398 | ||
469 | /** | ||
470 | * v4l2_m2m_expbuf() - export a source or destination buffer, depending on | ||
471 | * the type | ||
472 | */ | ||
473 | int v4l2_m2m_expbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | 399 | int v4l2_m2m_expbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, |
474 | struct v4l2_exportbuffer *eb) | 400 | struct v4l2_exportbuffer *eb) |
475 | { | 401 | { |
@@ -479,9 +405,7 @@ int v4l2_m2m_expbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |||
479 | return vb2_expbuf(vq, eb); | 405 | return vb2_expbuf(vq, eb); |
480 | } | 406 | } |
481 | EXPORT_SYMBOL_GPL(v4l2_m2m_expbuf); | 407 | EXPORT_SYMBOL_GPL(v4l2_m2m_expbuf); |
482 | /** | 408 | |
483 | * v4l2_m2m_streamon() - turn on streaming for a video queue | ||
484 | */ | ||
485 | int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | 409 | int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, |
486 | enum v4l2_buf_type type) | 410 | enum v4l2_buf_type type) |
487 | { | 411 | { |
@@ -497,9 +421,6 @@ int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |||
497 | } | 421 | } |
498 | EXPORT_SYMBOL_GPL(v4l2_m2m_streamon); | 422 | EXPORT_SYMBOL_GPL(v4l2_m2m_streamon); |
499 | 423 | ||
500 | /** | ||
501 | * v4l2_m2m_streamoff() - turn off streaming for a video queue | ||
502 | */ | ||
503 | int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | 424 | int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, |
504 | enum v4l2_buf_type type) | 425 | enum v4l2_buf_type type) |
505 | { | 426 | { |
@@ -540,14 +461,6 @@ int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |||
540 | } | 461 | } |
541 | EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff); | 462 | EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff); |
542 | 463 | ||
543 | /** | ||
544 | * v4l2_m2m_poll() - poll replacement, for destination buffers only | ||
545 | * | ||
546 | * Call from the driver's poll() function. Will poll both queues. If a buffer | ||
547 | * is available to dequeue (with dqbuf) from the source queue, this will | ||
548 | * indicate that a non-blocking write can be performed, while read will be | ||
549 | * returned in case of the destination queue. | ||
550 | */ | ||
551 | unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | 464 | unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, |
552 | struct poll_table_struct *wait) | 465 | struct poll_table_struct *wait) |
553 | { | 466 | { |
@@ -626,16 +539,6 @@ end: | |||
626 | } | 539 | } |
627 | EXPORT_SYMBOL_GPL(v4l2_m2m_poll); | 540 | EXPORT_SYMBOL_GPL(v4l2_m2m_poll); |
628 | 541 | ||
629 | /** | ||
630 | * v4l2_m2m_mmap() - source and destination queues-aware mmap multiplexer | ||
631 | * | ||
632 | * Call from driver's mmap() function. Will handle mmap() for both queues | ||
633 | * seamlessly for videobuffer, which will receive normal per-queue offsets and | ||
634 | * proper videobuf queue pointers. The differentiation is made outside videobuf | ||
635 | * by adding a predefined offset to buffers from one of the queues and | ||
636 | * subtracting it before passing it back to videobuf. Only drivers (and | ||
637 | * thus applications) receive modified offsets. | ||
638 | */ | ||
639 | int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | 542 | int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, |
640 | struct vm_area_struct *vma) | 543 | struct vm_area_struct *vma) |
641 | { | 544 | { |
@@ -653,11 +556,6 @@ int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |||
653 | } | 556 | } |
654 | EXPORT_SYMBOL(v4l2_m2m_mmap); | 557 | EXPORT_SYMBOL(v4l2_m2m_mmap); |
655 | 558 | ||
656 | /** | ||
657 | * v4l2_m2m_init() - initialize per-driver m2m data | ||
658 | * | ||
659 | * Usually called from driver's probe() function. | ||
660 | */ | ||
661 | struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops) | 559 | struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops) |
662 | { | 560 | { |
663 | struct v4l2_m2m_dev *m2m_dev; | 561 | struct v4l2_m2m_dev *m2m_dev; |
@@ -679,26 +577,12 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops) | |||
679 | } | 577 | } |
680 | EXPORT_SYMBOL_GPL(v4l2_m2m_init); | 578 | EXPORT_SYMBOL_GPL(v4l2_m2m_init); |
681 | 579 | ||
682 | /** | ||
683 | * v4l2_m2m_release() - cleans up and frees a m2m_dev structure | ||
684 | * | ||
685 | * Usually called from driver's remove() function. | ||
686 | */ | ||
687 | void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev) | 580 | void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev) |
688 | { | 581 | { |
689 | kfree(m2m_dev); | 582 | kfree(m2m_dev); |
690 | } | 583 | } |
691 | EXPORT_SYMBOL_GPL(v4l2_m2m_release); | 584 | EXPORT_SYMBOL_GPL(v4l2_m2m_release); |
692 | 585 | ||
693 | /** | ||
694 | * v4l2_m2m_ctx_init() - allocate and initialize a m2m context | ||
695 | * @priv - driver's instance private data | ||
696 | * @m2m_dev - a previously initialized m2m_dev struct | ||
697 | * @vq_init - a callback for queue type-specific initialization function to be | ||
698 | * used for initializing videobuf_queues | ||
699 | * | ||
700 | * Usually called from driver's open() function. | ||
701 | */ | ||
702 | struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev, | 586 | struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev, |
703 | void *drv_priv, | 587 | void *drv_priv, |
704 | int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)) | 588 | int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)) |
@@ -744,11 +628,6 @@ err: | |||
744 | } | 628 | } |
745 | EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_init); | 629 | EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_init); |
746 | 630 | ||
747 | /** | ||
748 | * v4l2_m2m_ctx_release() - release m2m context | ||
749 | * | ||
750 | * Usually called from driver's release() function. | ||
751 | */ | ||
752 | void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx) | 631 | void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx) |
753 | { | 632 | { |
754 | /* wait until the current context is dequeued from job_queue */ | 633 | /* wait until the current context is dequeued from job_queue */ |
@@ -761,11 +640,6 @@ void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx) | |||
761 | } | 640 | } |
762 | EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_release); | 641 | EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_release); |
763 | 642 | ||
764 | /** | ||
765 | * v4l2_m2m_buf_queue() - add a buffer to the proper ready buffers list. | ||
766 | * | ||
767 | * Call from buf_queue(), videobuf_queue_ops callback. | ||
768 | */ | ||
769 | void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, | 643 | void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, |
770 | struct vb2_v4l2_buffer *vbuf) | 644 | struct vb2_v4l2_buffer *vbuf) |
771 | { | 645 | { |
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index ca8ffeb56d72..21900202ff83 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c | |||
@@ -198,6 +198,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) | |||
198 | q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | 198 | q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; |
199 | void *mem_priv; | 199 | void *mem_priv; |
200 | int plane; | 200 | int plane; |
201 | int ret = -ENOMEM; | ||
201 | 202 | ||
202 | /* | 203 | /* |
203 | * Allocate memory for all planes in this buffer | 204 | * Allocate memory for all planes in this buffer |
@@ -209,8 +210,11 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) | |||
209 | mem_priv = call_ptr_memop(vb, alloc, | 210 | mem_priv = call_ptr_memop(vb, alloc, |
210 | q->alloc_devs[plane] ? : q->dev, | 211 | q->alloc_devs[plane] ? : q->dev, |
211 | q->dma_attrs, size, dma_dir, q->gfp_flags); | 212 | q->dma_attrs, size, dma_dir, q->gfp_flags); |
212 | if (IS_ERR_OR_NULL(mem_priv)) | 213 | if (IS_ERR(mem_priv)) { |
214 | if (mem_priv) | ||
215 | ret = PTR_ERR(mem_priv); | ||
213 | goto free; | 216 | goto free; |
217 | } | ||
214 | 218 | ||
215 | /* Associate allocator private data with this plane */ | 219 | /* Associate allocator private data with this plane */ |
216 | vb->planes[plane].mem_priv = mem_priv; | 220 | vb->planes[plane].mem_priv = mem_priv; |
@@ -224,7 +228,7 @@ free: | |||
224 | vb->planes[plane - 1].mem_priv = NULL; | 228 | vb->planes[plane - 1].mem_priv = NULL; |
225 | } | 229 | } |
226 | 230 | ||
227 | return -ENOMEM; | 231 | return ret; |
228 | } | 232 | } |
229 | 233 | ||
230 | /** | 234 | /** |
@@ -524,10 +528,6 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) | |||
524 | return 0; | 528 | return 0; |
525 | } | 529 | } |
526 | 530 | ||
527 | /** | ||
528 | * vb2_buffer_in_use() - return true if the buffer is in use and | ||
529 | * the queue cannot be freed (by the means of REQBUFS(0)) call | ||
530 | */ | ||
531 | bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb) | 531 | bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb) |
532 | { | 532 | { |
533 | unsigned int plane; | 533 | unsigned int plane; |
@@ -560,16 +560,6 @@ static bool __buffers_in_use(struct vb2_queue *q) | |||
560 | return false; | 560 | return false; |
561 | } | 561 | } |
562 | 562 | ||
563 | /** | ||
564 | * vb2_core_querybuf() - query video buffer information | ||
565 | * @q: videobuf queue | ||
566 | * @index: id number of the buffer | ||
567 | * @pb: buffer struct passed from userspace | ||
568 | * | ||
569 | * Should be called from vidioc_querybuf ioctl handler in driver. | ||
570 | * The passed buffer should have been verified. | ||
571 | * This function fills the relevant information for the userspace. | ||
572 | */ | ||
573 | void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb) | 563 | void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb) |
574 | { | 564 | { |
575 | call_void_bufop(q, fill_user_buffer, q->bufs[index], pb); | 565 | call_void_bufop(q, fill_user_buffer, q->bufs[index], pb); |
@@ -616,10 +606,6 @@ static int __verify_dmabuf_ops(struct vb2_queue *q) | |||
616 | return 0; | 606 | return 0; |
617 | } | 607 | } |
618 | 608 | ||
619 | /** | ||
620 | * vb2_verify_memory_type() - Check whether the memory type and buffer type | ||
621 | * passed to a buffer operation are compatible with the queue. | ||
622 | */ | ||
623 | int vb2_verify_memory_type(struct vb2_queue *q, | 609 | int vb2_verify_memory_type(struct vb2_queue *q, |
624 | enum vb2_memory memory, unsigned int type) | 610 | enum vb2_memory memory, unsigned int type) |
625 | { | 611 | { |
@@ -666,30 +652,6 @@ int vb2_verify_memory_type(struct vb2_queue *q, | |||
666 | } | 652 | } |
667 | EXPORT_SYMBOL(vb2_verify_memory_type); | 653 | EXPORT_SYMBOL(vb2_verify_memory_type); |
668 | 654 | ||
669 | /** | ||
670 | * vb2_core_reqbufs() - Initiate streaming | ||
671 | * @q: videobuf2 queue | ||
672 | * @memory: memory type | ||
673 | * @count: requested buffer count | ||
674 | * | ||
675 | * Should be called from vidioc_reqbufs ioctl handler of a driver. | ||
676 | * This function: | ||
677 | * 1) verifies streaming parameters passed from the userspace, | ||
678 | * 2) sets up the queue, | ||
679 | * 3) negotiates number of buffers and planes per buffer with the driver | ||
680 | * to be used during streaming, | ||
681 | * 4) allocates internal buffer structures (struct vb2_buffer), according to | ||
682 | * the agreed parameters, | ||
683 | * 5) for MMAP memory type, allocates actual video memory, using the | ||
684 | * memory handling/allocation routines provided during queue initialization | ||
685 | * | ||
686 | * If req->count is 0, all the memory will be freed instead. | ||
687 | * If the queue has been allocated previously (by a previous vb2_reqbufs) call | ||
688 | * and the queue is not busy, memory will be reallocated. | ||
689 | * | ||
690 | * The return values from this function are intended to be directly returned | ||
691 | * from vidioc_reqbufs handler in driver. | ||
692 | */ | ||
693 | int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, | 655 | int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, |
694 | unsigned int *count) | 656 | unsigned int *count) |
695 | { | 657 | { |
@@ -815,22 +777,6 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, | |||
815 | } | 777 | } |
816 | EXPORT_SYMBOL_GPL(vb2_core_reqbufs); | 778 | EXPORT_SYMBOL_GPL(vb2_core_reqbufs); |
817 | 779 | ||
818 | /** | ||
819 | * vb2_core_create_bufs() - Allocate buffers and any required auxiliary structs | ||
820 | * @q: videobuf2 queue | ||
821 | * @memory: memory type | ||
822 | * @count: requested buffer count | ||
823 | * @parg: parameter passed to device driver | ||
824 | * | ||
825 | * Should be called from vidioc_create_bufs ioctl handler of a driver. | ||
826 | * This function: | ||
827 | * 1) verifies parameter sanity | ||
828 | * 2) calls the .queue_setup() queue operation | ||
829 | * 3) performs any necessary memory allocations | ||
830 | * | ||
831 | * The return values from this function are intended to be directly returned | ||
832 | * from vidioc_create_bufs handler in driver. | ||
833 | */ | ||
834 | int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, | 780 | int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, |
835 | unsigned int *count, unsigned requested_planes, | 781 | unsigned int *count, unsigned requested_planes, |
836 | const unsigned requested_sizes[]) | 782 | const unsigned requested_sizes[]) |
@@ -920,14 +866,6 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, | |||
920 | } | 866 | } |
921 | EXPORT_SYMBOL_GPL(vb2_core_create_bufs); | 867 | EXPORT_SYMBOL_GPL(vb2_core_create_bufs); |
922 | 868 | ||
923 | /** | ||
924 | * vb2_plane_vaddr() - Return a kernel virtual address of a given plane | ||
925 | * @vb: vb2_buffer to which the plane in question belongs to | ||
926 | * @plane_no: plane number for which the address is to be returned | ||
927 | * | ||
928 | * This function returns a kernel virtual address of a given plane if | ||
929 | * such a mapping exist, NULL otherwise. | ||
930 | */ | ||
931 | void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no) | 869 | void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no) |
932 | { | 870 | { |
933 | if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) | 871 | if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) |
@@ -938,17 +876,6 @@ void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no) | |||
938 | } | 876 | } |
939 | EXPORT_SYMBOL_GPL(vb2_plane_vaddr); | 877 | EXPORT_SYMBOL_GPL(vb2_plane_vaddr); |
940 | 878 | ||
941 | /** | ||
942 | * vb2_plane_cookie() - Return allocator specific cookie for the given plane | ||
943 | * @vb: vb2_buffer to which the plane in question belongs to | ||
944 | * @plane_no: plane number for which the cookie is to be returned | ||
945 | * | ||
946 | * This function returns an allocator specific cookie for a given plane if | ||
947 | * available, NULL otherwise. The allocator should provide some simple static | ||
948 | * inline function, which would convert this cookie to the allocator specific | ||
949 | * type that can be used directly by the driver to access the buffer. This can | ||
950 | * be for example physical address, pointer to scatter list or IOMMU mapping. | ||
951 | */ | ||
952 | void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) | 879 | void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) |
953 | { | 880 | { |
954 | if (plane_no >= vb->num_planes || !vb->planes[plane_no].mem_priv) | 881 | if (plane_no >= vb->num_planes || !vb->planes[plane_no].mem_priv) |
@@ -958,26 +885,6 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) | |||
958 | } | 885 | } |
959 | EXPORT_SYMBOL_GPL(vb2_plane_cookie); | 886 | EXPORT_SYMBOL_GPL(vb2_plane_cookie); |
960 | 887 | ||
961 | /** | ||
962 | * vb2_buffer_done() - inform videobuf that an operation on a buffer is finished | ||
963 | * @vb: vb2_buffer returned from the driver | ||
964 | * @state: either VB2_BUF_STATE_DONE if the operation finished successfully, | ||
965 | * VB2_BUF_STATE_ERROR if the operation finished with an error or | ||
966 | * VB2_BUF_STATE_QUEUED if the driver wants to requeue buffers. | ||
967 | * If start_streaming fails then it should return buffers with state | ||
968 | * VB2_BUF_STATE_QUEUED to put them back into the queue. | ||
969 | * | ||
970 | * This function should be called by the driver after a hardware operation on | ||
971 | * a buffer is finished and the buffer may be returned to userspace. The driver | ||
972 | * cannot use this buffer anymore until it is queued back to it by videobuf | ||
973 | * by the means of buf_queue callback. Only buffers previously queued to the | ||
974 | * driver by buf_queue can be passed to this function. | ||
975 | * | ||
976 | * While streaming a buffer can only be returned in state DONE or ERROR. | ||
977 | * The start_streaming op can also return them in case the DMA engine cannot | ||
978 | * be started for some reason. In that case the buffers should be returned with | ||
979 | * state QUEUED. | ||
980 | */ | ||
981 | void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) | 888 | void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) |
982 | { | 889 | { |
983 | struct vb2_queue *q = vb->vb2_queue; | 890 | struct vb2_queue *q = vb->vb2_queue; |
@@ -1036,18 +943,6 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) | |||
1036 | } | 943 | } |
1037 | EXPORT_SYMBOL_GPL(vb2_buffer_done); | 944 | EXPORT_SYMBOL_GPL(vb2_buffer_done); |
1038 | 945 | ||
1039 | /** | ||
1040 | * vb2_discard_done() - discard all buffers marked as DONE | ||
1041 | * @q: videobuf2 queue | ||
1042 | * | ||
1043 | * This function is intended to be used with suspend/resume operations. It | ||
1044 | * discards all 'done' buffers as they would be too old to be requested after | ||
1045 | * resume. | ||
1046 | * | ||
1047 | * Drivers must stop the hardware and synchronize with interrupt handlers and/or | ||
1048 | * delayed works before calling this function to make sure no buffer will be | ||
1049 | * touched by the driver and/or hardware. | ||
1050 | */ | ||
1051 | void vb2_discard_done(struct vb2_queue *q) | 946 | void vb2_discard_done(struct vb2_queue *q) |
1052 | { | 947 | { |
1053 | struct vb2_buffer *vb; | 948 | struct vb2_buffer *vb; |
@@ -1136,10 +1031,10 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb) | |||
1136 | q->alloc_devs[plane] ? : q->dev, | 1031 | q->alloc_devs[plane] ? : q->dev, |
1137 | planes[plane].m.userptr, | 1032 | planes[plane].m.userptr, |
1138 | planes[plane].length, dma_dir); | 1033 | planes[plane].length, dma_dir); |
1139 | if (IS_ERR_OR_NULL(mem_priv)) { | 1034 | if (IS_ERR(mem_priv)) { |
1140 | dprintk(1, "failed acquiring userspace " | 1035 | dprintk(1, "failed acquiring userspace " |
1141 | "memory for plane %d\n", plane); | 1036 | "memory for plane %d\n", plane); |
1142 | ret = mem_priv ? PTR_ERR(mem_priv) : -EINVAL; | 1037 | ret = PTR_ERR(mem_priv); |
1143 | goto err; | 1038 | goto err; |
1144 | } | 1039 | } |
1145 | vb->planes[plane].mem_priv = mem_priv; | 1040 | vb->planes[plane].mem_priv = mem_priv; |
@@ -1228,8 +1123,10 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb) | |||
1228 | planes[plane].length = dbuf->size; | 1123 | planes[plane].length = dbuf->size; |
1229 | 1124 | ||
1230 | if (planes[plane].length < vb->planes[plane].min_length) { | 1125 | if (planes[plane].length < vb->planes[plane].min_length) { |
1231 | dprintk(1, "invalid dmabuf length for plane %d\n", | 1126 | dprintk(1, "invalid dmabuf length %u for plane %d, " |
1232 | plane); | 1127 | "minimum length %u\n", |
1128 | planes[plane].length, plane, | ||
1129 | vb->planes[plane].min_length); | ||
1233 | dma_buf_put(dbuf); | 1130 | dma_buf_put(dbuf); |
1234 | ret = -EINVAL; | 1131 | ret = -EINVAL; |
1235 | goto err; | 1132 | goto err; |
@@ -1271,9 +1168,10 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb) | |||
1271 | vb->planes[plane].mem_priv = mem_priv; | 1168 | vb->planes[plane].mem_priv = mem_priv; |
1272 | } | 1169 | } |
1273 | 1170 | ||
1274 | /* TODO: This pins the buffer(s) with dma_buf_map_attachment()).. but | 1171 | /* |
1275 | * really we want to do this just before the DMA, not while queueing | 1172 | * This pins the buffer(s) with dma_buf_map_attachment()). It's done |
1276 | * the buffer(s).. | 1173 | * here instead just before the DMA, while queueing the buffer(s) so |
1174 | * userspace knows sooner rather than later if the dma-buf map fails. | ||
1277 | */ | 1175 | */ |
1278 | for (plane = 0; plane < vb->num_planes; ++plane) { | 1176 | for (plane = 0; plane < vb->num_planes; ++plane) { |
1279 | ret = call_memop(vb, map_dmabuf, vb->planes[plane].mem_priv); | 1177 | ret = call_memop(vb, map_dmabuf, vb->planes[plane].mem_priv); |
@@ -1377,22 +1275,6 @@ static int __buf_prepare(struct vb2_buffer *vb, const void *pb) | |||
1377 | return ret; | 1275 | return ret; |
1378 | } | 1276 | } |
1379 | 1277 | ||
1380 | /** | ||
1381 | * vb2_core_prepare_buf() - Pass ownership of a buffer from userspace | ||
1382 | * to the kernel | ||
1383 | * @q: videobuf2 queue | ||
1384 | * @index: id number of the buffer | ||
1385 | * @pb: buffer structure passed from userspace to vidioc_prepare_buf | ||
1386 | * handler in driver | ||
1387 | * | ||
1388 | * Should be called from vidioc_prepare_buf ioctl handler of a driver. | ||
1389 | * The passed buffer should have been verified. | ||
1390 | * This function calls buf_prepare callback in the driver (if provided), | ||
1391 | * in which driver-specific buffer initialization can be performed, | ||
1392 | * | ||
1393 | * The return values from this function are intended to be directly returned | ||
1394 | * from vidioc_prepare_buf handler in driver. | ||
1395 | */ | ||
1396 | int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb) | 1278 | int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb) |
1397 | { | 1279 | { |
1398 | struct vb2_buffer *vb; | 1280 | struct vb2_buffer *vb; |
@@ -1481,24 +1363,6 @@ static int vb2_start_streaming(struct vb2_queue *q) | |||
1481 | return ret; | 1363 | return ret; |
1482 | } | 1364 | } |
1483 | 1365 | ||
1484 | /** | ||
1485 | * vb2_core_qbuf() - Queue a buffer from userspace | ||
1486 | * @q: videobuf2 queue | ||
1487 | * @index: id number of the buffer | ||
1488 | * @pb: buffer structure passed from userspace to vidioc_qbuf handler | ||
1489 | * in driver | ||
1490 | * | ||
1491 | * Should be called from vidioc_qbuf ioctl handler of a driver. | ||
1492 | * The passed buffer should have been verified. | ||
1493 | * This function: | ||
1494 | * 1) if necessary, calls buf_prepare callback in the driver (if provided), in | ||
1495 | * which driver-specific buffer initialization can be performed, | ||
1496 | * 2) if streaming is on, queues the buffer in driver by the means of buf_queue | ||
1497 | * callback for processing. | ||
1498 | * | ||
1499 | * The return values from this function are intended to be directly returned | ||
1500 | * from vidioc_qbuf handler in driver. | ||
1501 | */ | ||
1502 | int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb) | 1366 | int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb) |
1503 | { | 1367 | { |
1504 | struct vb2_buffer *vb; | 1368 | struct vb2_buffer *vb; |
@@ -1679,15 +1543,6 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, | |||
1679 | return ret; | 1543 | return ret; |
1680 | } | 1544 | } |
1681 | 1545 | ||
1682 | /** | ||
1683 | * vb2_wait_for_all_buffers() - wait until all buffers are given back to vb2 | ||
1684 | * @q: videobuf2 queue | ||
1685 | * | ||
1686 | * This function will wait until all buffers that have been given to the driver | ||
1687 | * by buf_queue() are given back to vb2 with vb2_buffer_done(). It doesn't call | ||
1688 | * wait_prepare, wait_finish pair. It is intended to be called with all locks | ||
1689 | * taken, for example from stop_streaming() callback. | ||
1690 | */ | ||
1691 | int vb2_wait_for_all_buffers(struct vb2_queue *q) | 1546 | int vb2_wait_for_all_buffers(struct vb2_queue *q) |
1692 | { | 1547 | { |
1693 | if (!q->streaming) { | 1548 | if (!q->streaming) { |
@@ -1725,27 +1580,6 @@ static void __vb2_dqbuf(struct vb2_buffer *vb) | |||
1725 | } | 1580 | } |
1726 | } | 1581 | } |
1727 | 1582 | ||
1728 | /** | ||
1729 | * vb2_dqbuf() - Dequeue a buffer to the userspace | ||
1730 | * @q: videobuf2 queue | ||
1731 | * @pb: buffer structure passed from userspace to vidioc_dqbuf handler | ||
1732 | * in driver | ||
1733 | * @nonblocking: if true, this call will not sleep waiting for a buffer if no | ||
1734 | * buffers ready for dequeuing are present. Normally the driver | ||
1735 | * would be passing (file->f_flags & O_NONBLOCK) here | ||
1736 | * | ||
1737 | * Should be called from vidioc_dqbuf ioctl handler of a driver. | ||
1738 | * The passed buffer should have been verified. | ||
1739 | * This function: | ||
1740 | * 1) calls buf_finish callback in the driver (if provided), in which | ||
1741 | * driver can perform any additional operations that may be required before | ||
1742 | * returning the buffer to userspace, such as cache sync, | ||
1743 | * 2) the buffer struct members are filled with relevant information for | ||
1744 | * the userspace. | ||
1745 | * | ||
1746 | * The return values from this function are intended to be directly returned | ||
1747 | * from vidioc_dqbuf handler in driver. | ||
1748 | */ | ||
1749 | int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb, | 1583 | int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb, |
1750 | bool nonblocking) | 1584 | bool nonblocking) |
1751 | { | 1585 | { |
@@ -1909,19 +1743,6 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type) | |||
1909 | } | 1743 | } |
1910 | EXPORT_SYMBOL_GPL(vb2_core_streamon); | 1744 | EXPORT_SYMBOL_GPL(vb2_core_streamon); |
1911 | 1745 | ||
1912 | /** | ||
1913 | * vb2_queue_error() - signal a fatal error on the queue | ||
1914 | * @q: videobuf2 queue | ||
1915 | * | ||
1916 | * Flag that a fatal unrecoverable error has occurred and wake up all processes | ||
1917 | * waiting on the queue. Polling will now set POLLERR and queuing and dequeuing | ||
1918 | * buffers will return -EIO. | ||
1919 | * | ||
1920 | * The error flag will be cleared when cancelling the queue, either from | ||
1921 | * vb2_streamoff or vb2_queue_release. Drivers should thus not call this | ||
1922 | * function before starting the stream, otherwise the error flag will remain set | ||
1923 | * until the queue is released when closing the device node. | ||
1924 | */ | ||
1925 | void vb2_queue_error(struct vb2_queue *q) | 1746 | void vb2_queue_error(struct vb2_queue *q) |
1926 | { | 1747 | { |
1927 | q->error = 1; | 1748 | q->error = 1; |
@@ -1984,19 +1805,6 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, | |||
1984 | return -EINVAL; | 1805 | return -EINVAL; |
1985 | } | 1806 | } |
1986 | 1807 | ||
1987 | /** | ||
1988 | * vb2_core_expbuf() - Export a buffer as a file descriptor | ||
1989 | * @q: videobuf2 queue | ||
1990 | * @fd: file descriptor associated with DMABUF (set by driver) * | ||
1991 | * @type: buffer type | ||
1992 | * @index: id number of the buffer | ||
1993 | * @plane: index of the plane to be exported, 0 for single plane queues | ||
1994 | * @flags: flags for newly created file, currently only O_CLOEXEC is | ||
1995 | * supported, refer to manual of open syscall for more details | ||
1996 | * | ||
1997 | * The return values from this function are intended to be directly returned | ||
1998 | * from vidioc_expbuf handler in driver. | ||
1999 | */ | ||
2000 | int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, | 1808 | int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, |
2001 | unsigned int index, unsigned int plane, unsigned int flags) | 1809 | unsigned int index, unsigned int plane, unsigned int flags) |
2002 | { | 1810 | { |
@@ -2068,25 +1876,6 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, | |||
2068 | } | 1876 | } |
2069 | EXPORT_SYMBOL_GPL(vb2_core_expbuf); | 1877 | EXPORT_SYMBOL_GPL(vb2_core_expbuf); |
2070 | 1878 | ||
2071 | /** | ||
2072 | * vb2_mmap() - map video buffers into application address space | ||
2073 | * @q: videobuf2 queue | ||
2074 | * @vma: vma passed to the mmap file operation handler in the driver | ||
2075 | * | ||
2076 | * Should be called from mmap file operation handler of a driver. | ||
2077 | * This function maps one plane of one of the available video buffers to | ||
2078 | * userspace. To map whole video memory allocated on reqbufs, this function | ||
2079 | * has to be called once per each plane per each buffer previously allocated. | ||
2080 | * | ||
2081 | * When the userspace application calls mmap, it passes to it an offset returned | ||
2082 | * to it earlier by the means of vidioc_querybuf handler. That offset acts as | ||
2083 | * a "cookie", which is then used to identify the plane to be mapped. | ||
2084 | * This function finds a plane with a matching offset and a mapping is performed | ||
2085 | * by the means of a provided memory operation. | ||
2086 | * | ||
2087 | * The return values from this function are intended to be directly returned | ||
2088 | * from the mmap handler in driver. | ||
2089 | */ | ||
2090 | int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) | 1879 | int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) |
2091 | { | 1880 | { |
2092 | unsigned long off = vma->vm_pgoff << PAGE_SHIFT; | 1881 | unsigned long off = vma->vm_pgoff << PAGE_SHIFT; |
@@ -2188,17 +1977,6 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, | |||
2188 | EXPORT_SYMBOL_GPL(vb2_get_unmapped_area); | 1977 | EXPORT_SYMBOL_GPL(vb2_get_unmapped_area); |
2189 | #endif | 1978 | #endif |
2190 | 1979 | ||
2191 | /** | ||
2192 | * vb2_core_queue_init() - initialize a videobuf2 queue | ||
2193 | * @q: videobuf2 queue; this structure should be allocated in driver | ||
2194 | * | ||
2195 | * The vb2_queue structure should be allocated by the driver. The driver is | ||
2196 | * responsible of clearing it's content and setting initial values for some | ||
2197 | * required entries before calling this function. | ||
2198 | * q->ops, q->mem_ops, q->type and q->io_modes are mandatory. Please refer | ||
2199 | * to the struct vb2_queue description in include/media/videobuf2-core.h | ||
2200 | * for more information. | ||
2201 | */ | ||
2202 | int vb2_core_queue_init(struct vb2_queue *q) | 1980 | int vb2_core_queue_init(struct vb2_queue *q) |
2203 | { | 1981 | { |
2204 | /* | 1982 | /* |
@@ -2228,14 +2006,6 @@ EXPORT_SYMBOL_GPL(vb2_core_queue_init); | |||
2228 | 2006 | ||
2229 | static int __vb2_init_fileio(struct vb2_queue *q, int read); | 2007 | static int __vb2_init_fileio(struct vb2_queue *q, int read); |
2230 | static int __vb2_cleanup_fileio(struct vb2_queue *q); | 2008 | static int __vb2_cleanup_fileio(struct vb2_queue *q); |
2231 | /** | ||
2232 | * vb2_core_queue_release() - stop streaming, release the queue and free memory | ||
2233 | * @q: videobuf2 queue | ||
2234 | * | ||
2235 | * This function stops streaming and performs necessary clean ups, including | ||
2236 | * freeing video buffer memory. The driver is responsible for freeing | ||
2237 | * the vb2_queue structure itself. | ||
2238 | */ | ||
2239 | void vb2_core_queue_release(struct vb2_queue *q) | 2009 | void vb2_core_queue_release(struct vb2_queue *q) |
2240 | { | 2010 | { |
2241 | __vb2_cleanup_fileio(q); | 2011 | __vb2_cleanup_fileio(q); |
@@ -2246,22 +2016,6 @@ void vb2_core_queue_release(struct vb2_queue *q) | |||
2246 | } | 2016 | } |
2247 | EXPORT_SYMBOL_GPL(vb2_core_queue_release); | 2017 | EXPORT_SYMBOL_GPL(vb2_core_queue_release); |
2248 | 2018 | ||
2249 | /** | ||
2250 | * vb2_core_poll() - implements poll userspace operation | ||
2251 | * @q: videobuf2 queue | ||
2252 | * @file: file argument passed to the poll file operation handler | ||
2253 | * @wait: wait argument passed to the poll file operation handler | ||
2254 | * | ||
2255 | * This function implements poll file operation handler for a driver. | ||
2256 | * For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will | ||
2257 | * be informed that the file descriptor of a video device is available for | ||
2258 | * reading. | ||
2259 | * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor | ||
2260 | * will be reported as available for writing. | ||
2261 | * | ||
2262 | * The return values from this function are intended to be directly returned | ||
2263 | * from poll handler in driver. | ||
2264 | */ | ||
2265 | unsigned int vb2_core_poll(struct vb2_queue *q, struct file *file, | 2019 | unsigned int vb2_core_poll(struct vb2_queue *q, struct file *file, |
2266 | poll_table *wait) | 2020 | poll_table *wait) |
2267 | { | 2021 | { |
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 59fa204b15f3..fb6a177be461 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c | |||
@@ -141,6 +141,9 @@ static void *vb2_dc_alloc(struct device *dev, unsigned long attrs, | |||
141 | { | 141 | { |
142 | struct vb2_dc_buf *buf; | 142 | struct vb2_dc_buf *buf; |
143 | 143 | ||
144 | if (WARN_ON(!dev)) | ||
145 | return ERR_PTR(-EINVAL); | ||
146 | |||
144 | buf = kzalloc(sizeof *buf, GFP_KERNEL); | 147 | buf = kzalloc(sizeof *buf, GFP_KERNEL); |
145 | if (!buf) | 148 | if (!buf) |
146 | return ERR_PTR(-ENOMEM); | 149 | return ERR_PTR(-ENOMEM); |
@@ -493,6 +496,9 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr, | |||
493 | return ERR_PTR(-EINVAL); | 496 | return ERR_PTR(-EINVAL); |
494 | } | 497 | } |
495 | 498 | ||
499 | if (WARN_ON(!dev)) | ||
500 | return ERR_PTR(-EINVAL); | ||
501 | |||
496 | buf = kzalloc(sizeof *buf, GFP_KERNEL); | 502 | buf = kzalloc(sizeof *buf, GFP_KERNEL); |
497 | if (!buf) | 503 | if (!buf) |
498 | return ERR_PTR(-ENOMEM); | 504 | return ERR_PTR(-ENOMEM); |
@@ -673,6 +679,9 @@ static void *vb2_dc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, | |||
673 | if (dbuf->size < size) | 679 | if (dbuf->size < size) |
674 | return ERR_PTR(-EFAULT); | 680 | return ERR_PTR(-EFAULT); |
675 | 681 | ||
682 | if (WARN_ON(!dev)) | ||
683 | return ERR_PTR(-EINVAL); | ||
684 | |||
676 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); | 685 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); |
677 | if (!buf) | 686 | if (!buf) |
678 | return ERR_PTR(-ENOMEM); | 687 | return ERR_PTR(-ENOMEM); |
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index bd82d709ee82..ecff8f492c4f 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c | |||
@@ -104,11 +104,12 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs, | |||
104 | int ret; | 104 | int ret; |
105 | int num_pages; | 105 | int num_pages; |
106 | 106 | ||
107 | if (WARN_ON(dev == NULL)) | 107 | if (WARN_ON(!dev)) |
108 | return NULL; | 108 | return ERR_PTR(-EINVAL); |
109 | |||
109 | buf = kzalloc(sizeof *buf, GFP_KERNEL); | 110 | buf = kzalloc(sizeof *buf, GFP_KERNEL); |
110 | if (!buf) | 111 | if (!buf) |
111 | return NULL; | 112 | return ERR_PTR(-ENOMEM); |
112 | 113 | ||
113 | buf->vaddr = NULL; | 114 | buf->vaddr = NULL; |
114 | buf->dma_dir = dma_dir; | 115 | buf->dma_dir = dma_dir; |
@@ -166,7 +167,7 @@ fail_pages_alloc: | |||
166 | kfree(buf->pages); | 167 | kfree(buf->pages); |
167 | fail_pages_array_alloc: | 168 | fail_pages_array_alloc: |
168 | kfree(buf); | 169 | kfree(buf); |
169 | return NULL; | 170 | return ERR_PTR(-ENOMEM); |
170 | } | 171 | } |
171 | 172 | ||
172 | static void vb2_dma_sg_put(void *buf_priv) | 173 | static void vb2_dma_sg_put(void *buf_priv) |
@@ -224,9 +225,12 @@ static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr, | |||
224 | struct sg_table *sgt; | 225 | struct sg_table *sgt; |
225 | struct frame_vector *vec; | 226 | struct frame_vector *vec; |
226 | 227 | ||
228 | if (WARN_ON(!dev)) | ||
229 | return ERR_PTR(-EINVAL); | ||
230 | |||
227 | buf = kzalloc(sizeof *buf, GFP_KERNEL); | 231 | buf = kzalloc(sizeof *buf, GFP_KERNEL); |
228 | if (!buf) | 232 | if (!buf) |
229 | return NULL; | 233 | return ERR_PTR(-ENOMEM); |
230 | 234 | ||
231 | buf->vaddr = NULL; | 235 | buf->vaddr = NULL; |
232 | buf->dev = dev; | 236 | buf->dev = dev; |
@@ -266,7 +270,7 @@ userptr_fail_sgtable: | |||
266 | vb2_destroy_framevec(vec); | 270 | vb2_destroy_framevec(vec); |
267 | userptr_fail_pfnvec: | 271 | userptr_fail_pfnvec: |
268 | kfree(buf); | 272 | kfree(buf); |
269 | return NULL; | 273 | return ERR_PTR(-ENOMEM); |
270 | } | 274 | } |
271 | 275 | ||
272 | /* | 276 | /* |
@@ -606,6 +610,9 @@ static void *vb2_dma_sg_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, | |||
606 | struct vb2_dma_sg_buf *buf; | 610 | struct vb2_dma_sg_buf *buf; |
607 | struct dma_buf_attachment *dba; | 611 | struct dma_buf_attachment *dba; |
608 | 612 | ||
613 | if (WARN_ON(!dev)) | ||
614 | return ERR_PTR(-EINVAL); | ||
615 | |||
609 | if (dbuf->size < size) | 616 | if (dbuf->size < size) |
610 | return ERR_PTR(-EFAULT); | 617 | return ERR_PTR(-EFAULT); |
611 | 618 | ||
diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c index 9cfbb6e4bc28..52ef8833f6b6 100644 --- a/drivers/media/v4l2-core/videobuf2-v4l2.c +++ b/drivers/media/v4l2-core/videobuf2-v4l2.c | |||
@@ -483,13 +483,6 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) | |||
483 | } | 483 | } |
484 | EXPORT_SYMBOL(vb2_querybuf); | 484 | EXPORT_SYMBOL(vb2_querybuf); |
485 | 485 | ||
486 | /** | ||
487 | * vb2_reqbufs() - Wrapper for vb2_core_reqbufs() that also verifies | ||
488 | * the memory and type values. | ||
489 | * @q: videobuf2 queue | ||
490 | * @req: struct passed from userspace to vidioc_reqbufs handler | ||
491 | * in driver | ||
492 | */ | ||
493 | int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | 486 | int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) |
494 | { | 487 | { |
495 | int ret = vb2_verify_memory_type(q, req->memory, req->type); | 488 | int ret = vb2_verify_memory_type(q, req->memory, req->type); |
@@ -498,21 +491,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | |||
498 | } | 491 | } |
499 | EXPORT_SYMBOL_GPL(vb2_reqbufs); | 492 | EXPORT_SYMBOL_GPL(vb2_reqbufs); |
500 | 493 | ||
501 | /** | ||
502 | * vb2_prepare_buf() - Pass ownership of a buffer from userspace to the kernel | ||
503 | * @q: videobuf2 queue | ||
504 | * @b: buffer structure passed from userspace to vidioc_prepare_buf | ||
505 | * handler in driver | ||
506 | * | ||
507 | * Should be called from vidioc_prepare_buf ioctl handler of a driver. | ||
508 | * This function: | ||
509 | * 1) verifies the passed buffer, | ||
510 | * 2) calls buf_prepare callback in the driver (if provided), in which | ||
511 | * driver-specific buffer initialization can be performed, | ||
512 | * | ||
513 | * The return values from this function are intended to be directly returned | ||
514 | * from vidioc_prepare_buf handler in driver. | ||
515 | */ | ||
516 | int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) | 494 | int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) |
517 | { | 495 | { |
518 | int ret; | 496 | int ret; |
@@ -528,13 +506,6 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) | |||
528 | } | 506 | } |
529 | EXPORT_SYMBOL_GPL(vb2_prepare_buf); | 507 | EXPORT_SYMBOL_GPL(vb2_prepare_buf); |
530 | 508 | ||
531 | /** | ||
532 | * vb2_create_bufs() - Wrapper for vb2_core_create_bufs() that also verifies | ||
533 | * the memory and type values. | ||
534 | * @q: videobuf2 queue | ||
535 | * @create: creation parameters, passed from userspace to vidioc_create_bufs | ||
536 | * handler in driver | ||
537 | */ | ||
538 | int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) | 509 | int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) |
539 | { | 510 | { |
540 | unsigned requested_planes = 1; | 511 | unsigned requested_planes = 1; |
@@ -586,23 +557,6 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) | |||
586 | } | 557 | } |
587 | EXPORT_SYMBOL_GPL(vb2_create_bufs); | 558 | EXPORT_SYMBOL_GPL(vb2_create_bufs); |
588 | 559 | ||
589 | /** | ||
590 | * vb2_qbuf() - Queue a buffer from userspace | ||
591 | * @q: videobuf2 queue | ||
592 | * @b: buffer structure passed from userspace to vidioc_qbuf handler | ||
593 | * in driver | ||
594 | * | ||
595 | * Should be called from vidioc_qbuf ioctl handler of a driver. | ||
596 | * This function: | ||
597 | * 1) verifies the passed buffer, | ||
598 | * 2) if necessary, calls buf_prepare callback in the driver (if provided), in | ||
599 | * which driver-specific buffer initialization can be performed, | ||
600 | * 3) if streaming is on, queues the buffer in driver by the means of buf_queue | ||
601 | * callback for processing. | ||
602 | * | ||
603 | * The return values from this function are intended to be directly returned | ||
604 | * from vidioc_qbuf handler in driver. | ||
605 | */ | ||
606 | int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) | 560 | int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) |
607 | { | 561 | { |
608 | int ret; | 562 | int ret; |
@@ -617,27 +571,6 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) | |||
617 | } | 571 | } |
618 | EXPORT_SYMBOL_GPL(vb2_qbuf); | 572 | EXPORT_SYMBOL_GPL(vb2_qbuf); |
619 | 573 | ||
620 | /** | ||
621 | * vb2_dqbuf() - Dequeue a buffer to the userspace | ||
622 | * @q: videobuf2 queue | ||
623 | * @b: buffer structure passed from userspace to vidioc_dqbuf handler | ||
624 | * in driver | ||
625 | * @nonblocking: if true, this call will not sleep waiting for a buffer if no | ||
626 | * buffers ready for dequeuing are present. Normally the driver | ||
627 | * would be passing (file->f_flags & O_NONBLOCK) here | ||
628 | * | ||
629 | * Should be called from vidioc_dqbuf ioctl handler of a driver. | ||
630 | * This function: | ||
631 | * 1) verifies the passed buffer, | ||
632 | * 2) calls buf_finish callback in the driver (if provided), in which | ||
633 | * driver can perform any additional operations that may be required before | ||
634 | * returning the buffer to userspace, such as cache sync, | ||
635 | * 3) the buffer struct members are filled with relevant information for | ||
636 | * the userspace. | ||
637 | * | ||
638 | * The return values from this function are intended to be directly returned | ||
639 | * from vidioc_dqbuf handler in driver. | ||
640 | */ | ||
641 | int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) | 574 | int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) |
642 | { | 575 | { |
643 | int ret; | 576 | int ret; |
@@ -664,19 +597,6 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) | |||
664 | } | 597 | } |
665 | EXPORT_SYMBOL_GPL(vb2_dqbuf); | 598 | EXPORT_SYMBOL_GPL(vb2_dqbuf); |
666 | 599 | ||
667 | /** | ||
668 | * vb2_streamon - start streaming | ||
669 | * @q: videobuf2 queue | ||
670 | * @type: type argument passed from userspace to vidioc_streamon handler | ||
671 | * | ||
672 | * Should be called from vidioc_streamon handler of a driver. | ||
673 | * This function: | ||
674 | * 1) verifies current state | ||
675 | * 2) passes any previously queued buffers to the driver and starts streaming | ||
676 | * | ||
677 | * The return values from this function are intended to be directly returned | ||
678 | * from vidioc_streamon handler in the driver. | ||
679 | */ | ||
680 | int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) | 600 | int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) |
681 | { | 601 | { |
682 | if (vb2_fileio_is_active(q)) { | 602 | if (vb2_fileio_is_active(q)) { |
@@ -687,21 +607,6 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) | |||
687 | } | 607 | } |
688 | EXPORT_SYMBOL_GPL(vb2_streamon); | 608 | EXPORT_SYMBOL_GPL(vb2_streamon); |
689 | 609 | ||
690 | /** | ||
691 | * vb2_streamoff - stop streaming | ||
692 | * @q: videobuf2 queue | ||
693 | * @type: type argument passed from userspace to vidioc_streamoff handler | ||
694 | * | ||
695 | * Should be called from vidioc_streamoff handler of a driver. | ||
696 | * This function: | ||
697 | * 1) verifies current state, | ||
698 | * 2) stop streaming and dequeues any queued buffers, including those previously | ||
699 | * passed to the driver (after waiting for the driver to finish). | ||
700 | * | ||
701 | * This call can be used for pausing playback. | ||
702 | * The return values from this function are intended to be directly returned | ||
703 | * from vidioc_streamoff handler in the driver | ||
704 | */ | ||
705 | int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) | 610 | int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) |
706 | { | 611 | { |
707 | if (vb2_fileio_is_active(q)) { | 612 | if (vb2_fileio_is_active(q)) { |
@@ -712,15 +617,6 @@ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) | |||
712 | } | 617 | } |
713 | EXPORT_SYMBOL_GPL(vb2_streamoff); | 618 | EXPORT_SYMBOL_GPL(vb2_streamoff); |
714 | 619 | ||
715 | /** | ||
716 | * vb2_expbuf() - Export a buffer as a file descriptor | ||
717 | * @q: videobuf2 queue | ||
718 | * @eb: export buffer structure passed from userspace to vidioc_expbuf | ||
719 | * handler in driver | ||
720 | * | ||
721 | * The return values from this function are intended to be directly returned | ||
722 | * from vidioc_expbuf handler in driver. | ||
723 | */ | ||
724 | int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) | 620 | int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) |
725 | { | 621 | { |
726 | return vb2_core_expbuf(q, &eb->fd, eb->type, eb->index, | 622 | return vb2_core_expbuf(q, &eb->fd, eb->type, eb->index, |
@@ -728,17 +624,6 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) | |||
728 | } | 624 | } |
729 | EXPORT_SYMBOL_GPL(vb2_expbuf); | 625 | EXPORT_SYMBOL_GPL(vb2_expbuf); |
730 | 626 | ||
731 | /** | ||
732 | * vb2_queue_init() - initialize a videobuf2 queue | ||
733 | * @q: videobuf2 queue; this structure should be allocated in driver | ||
734 | * | ||
735 | * The vb2_queue structure should be allocated by the driver. The driver is | ||
736 | * responsible of clearing it's content and setting initial values for some | ||
737 | * required entries before calling this function. | ||
738 | * q->ops, q->mem_ops, q->type and q->io_modes are mandatory. Please refer | ||
739 | * to the struct vb2_queue description in include/media/videobuf2-core.h | ||
740 | * for more information. | ||
741 | */ | ||
742 | int vb2_queue_init(struct vb2_queue *q) | 627 | int vb2_queue_init(struct vb2_queue *q) |
743 | { | 628 | { |
744 | /* | 629 | /* |
@@ -779,39 +664,12 @@ int vb2_queue_init(struct vb2_queue *q) | |||
779 | } | 664 | } |
780 | EXPORT_SYMBOL_GPL(vb2_queue_init); | 665 | EXPORT_SYMBOL_GPL(vb2_queue_init); |
781 | 666 | ||
782 | /** | ||
783 | * vb2_queue_release() - stop streaming, release the queue and free memory | ||
784 | * @q: videobuf2 queue | ||
785 | * | ||
786 | * This function stops streaming and performs necessary clean ups, including | ||
787 | * freeing video buffer memory. The driver is responsible for freeing | ||
788 | * the vb2_queue structure itself. | ||
789 | */ | ||
790 | void vb2_queue_release(struct vb2_queue *q) | 667 | void vb2_queue_release(struct vb2_queue *q) |
791 | { | 668 | { |
792 | vb2_core_queue_release(q); | 669 | vb2_core_queue_release(q); |
793 | } | 670 | } |
794 | EXPORT_SYMBOL_GPL(vb2_queue_release); | 671 | EXPORT_SYMBOL_GPL(vb2_queue_release); |
795 | 672 | ||
796 | /** | ||
797 | * vb2_poll() - implements poll userspace operation | ||
798 | * @q: videobuf2 queue | ||
799 | * @file: file argument passed to the poll file operation handler | ||
800 | * @wait: wait argument passed to the poll file operation handler | ||
801 | * | ||
802 | * This function implements poll file operation handler for a driver. | ||
803 | * For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will | ||
804 | * be informed that the file descriptor of a video device is available for | ||
805 | * reading. | ||
806 | * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor | ||
807 | * will be reported as available for writing. | ||
808 | * | ||
809 | * If the driver uses struct v4l2_fh, then vb2_poll() will also check for any | ||
810 | * pending events. | ||
811 | * | ||
812 | * The return values from this function are intended to be directly returned | ||
813 | * from poll handler in driver. | ||
814 | */ | ||
815 | unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) | 673 | unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) |
816 | { | 674 | { |
817 | struct video_device *vfd = video_devdata(file); | 675 | struct video_device *vfd = video_devdata(file); |
diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index c2820a6e164d..ab3227b75c84 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c | |||
@@ -41,7 +41,7 @@ static void *vb2_vmalloc_alloc(struct device *dev, unsigned long attrs, | |||
41 | 41 | ||
42 | buf = kzalloc(sizeof(*buf), GFP_KERNEL | gfp_flags); | 42 | buf = kzalloc(sizeof(*buf), GFP_KERNEL | gfp_flags); |
43 | if (!buf) | 43 | if (!buf) |
44 | return NULL; | 44 | return ERR_PTR(-ENOMEM); |
45 | 45 | ||
46 | buf->size = size; | 46 | buf->size = size; |
47 | buf->vaddr = vmalloc_user(buf->size); | 47 | buf->vaddr = vmalloc_user(buf->size); |
@@ -53,7 +53,7 @@ static void *vb2_vmalloc_alloc(struct device *dev, unsigned long attrs, | |||
53 | if (!buf->vaddr) { | 53 | if (!buf->vaddr) { |
54 | pr_debug("vmalloc of size %ld failed\n", buf->size); | 54 | pr_debug("vmalloc of size %ld failed\n", buf->size); |
55 | kfree(buf); | 55 | kfree(buf); |
56 | return NULL; | 56 | return ERR_PTR(-ENOMEM); |
57 | } | 57 | } |
58 | 58 | ||
59 | atomic_inc(&buf->refcount); | 59 | atomic_inc(&buf->refcount); |
@@ -77,17 +77,20 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, | |||
77 | struct vb2_vmalloc_buf *buf; | 77 | struct vb2_vmalloc_buf *buf; |
78 | struct frame_vector *vec; | 78 | struct frame_vector *vec; |
79 | int n_pages, offset, i; | 79 | int n_pages, offset, i; |
80 | int ret = -ENOMEM; | ||
80 | 81 | ||
81 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); | 82 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); |
82 | if (!buf) | 83 | if (!buf) |
83 | return NULL; | 84 | return ERR_PTR(-ENOMEM); |
84 | 85 | ||
85 | buf->dma_dir = dma_dir; | 86 | buf->dma_dir = dma_dir; |
86 | offset = vaddr & ~PAGE_MASK; | 87 | offset = vaddr & ~PAGE_MASK; |
87 | buf->size = size; | 88 | buf->size = size; |
88 | vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE); | 89 | vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE); |
89 | if (IS_ERR(vec)) | 90 | if (IS_ERR(vec)) { |
91 | ret = PTR_ERR(vec); | ||
90 | goto fail_pfnvec_create; | 92 | goto fail_pfnvec_create; |
93 | } | ||
91 | buf->vec = vec; | 94 | buf->vec = vec; |
92 | n_pages = frame_vector_count(vec); | 95 | n_pages = frame_vector_count(vec); |
93 | if (frame_vector_to_pages(vec) < 0) { | 96 | if (frame_vector_to_pages(vec) < 0) { |
@@ -117,7 +120,7 @@ fail_map: | |||
117 | fail_pfnvec_create: | 120 | fail_pfnvec_create: |
118 | kfree(buf); | 121 | kfree(buf); |
119 | 122 | ||
120 | return NULL; | 123 | return ERR_PTR(ret); |
121 | } | 124 | } |
122 | 125 | ||
123 | static void vb2_vmalloc_put_userptr(void *buf_priv) | 126 | static void vb2_vmalloc_put_userptr(void *buf_priv) |