diff options
64 files changed, 1463 insertions, 1103 deletions
diff --git a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml index a78c9207422f..0ae0b6a915d0 100644 --- a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml @@ -62,28 +62,28 @@ buffer as a DMABUF file at any time after buffers have been allocated with the &VIDIOC-REQBUFS; ioctl.</para> <para> To export a buffer, applications fill &v4l2-exportbuffer;. The -<structfield> type </structfield> field is set to the same buffer type as was -previously used with &v4l2-requestbuffers;<structfield> type </structfield>. -Applications must also set the <structfield> index </structfield> field. Valid +<structfield>type</structfield> field is set to the same buffer type as was +previously used with &v4l2-requestbuffers; <structfield>type</structfield>. +Applications must also set the <structfield>index</structfield> field. Valid index numbers range from zero to the number of buffers allocated with -&VIDIOC-REQBUFS; (&v4l2-requestbuffers;<structfield> count </structfield>) -minus one. For the multi-planar API, applications set the <structfield> plane -</structfield> field to the index of the plane to be exported. Valid planes +&VIDIOC-REQBUFS; (&v4l2-requestbuffers; <structfield>count</structfield>) +minus one. For the multi-planar API, applications set the <structfield>plane</structfield> +field to the index of the plane to be exported. Valid planes range from zero to the maximal number of valid planes for the currently active -format. For the single-planar API, applications must set <structfield> plane -</structfield> to zero. Additional flags may be posted in the <structfield> -flags </structfield> field. Refer to a manual for open() for details. +format. For the single-planar API, applications must set <structfield>plane</structfield> +to zero. Additional flags may be posted in the <structfield>flags</structfield> +field. Refer to a manual for open() for details. Currently only O_CLOEXEC, O_RDONLY, O_WRONLY, and O_RDWR are supported. All other fields must be set to zero. In the case of multi-planar API, every plane is exported separately using -multiple <constant> VIDIOC_EXPBUF </constant> calls. </para> +multiple <constant>VIDIOC_EXPBUF</constant> calls.</para> -<para> After calling <constant>VIDIOC_EXPBUF</constant> the <structfield> fd -</structfield> field will be set by a driver. This is a DMABUF file +<para>After calling <constant>VIDIOC_EXPBUF</constant> the <structfield>fd</structfield> +field will be set by a driver. This is a DMABUF file descriptor. The application may pass it to other DMABUF-aware devices. Refer to <link linkend="dmabuf">DMABUF importing</link> for details about importing DMABUF files into V4L2 nodes. It is recommended to close a DMABUF file when it -is no longer used to allow the associated memory to be reclaimed. </para> +is no longer used to allow the associated memory to be reclaimed.</para> </refsect1> <refsect1> @@ -170,9 +170,9 @@ multi-planar API. Otherwise this value must be set to zero. </entry> <row> <entry>__u32</entry> <entry><structfield>flags</structfield></entry> - <entry>Flags for the newly created file, currently only <constant> -O_CLOEXEC </constant>, <constant>O_RDONLY</constant>, <constant>O_WRONLY -</constant>, and <constant>O_RDWR</constant> are supported, refer to the manual + <entry>Flags for the newly created file, currently only +<constant>O_CLOEXEC</constant>, <constant>O_RDONLY</constant>, <constant>O_WRONLY</constant>, +and <constant>O_RDWR</constant> are supported, refer to the manual of open() for more details.</entry> </row> <row> @@ -200,9 +200,9 @@ set the array to zero.</entry> <term><errorcode>EINVAL</errorcode></term> <listitem> <para>A queue is not in MMAP mode or DMABUF exporting is not -supported or <structfield> flags </structfield> or <structfield> type -</structfield> or <structfield> index </structfield> or <structfield> plane -</structfield> fields are invalid.</para> +supported or <structfield>flags</structfield> or <structfield>type</structfield> +or <structfield>index</structfield> or <structfield>plane</structfield> fields +are invalid.</para> </listitem> </varlistentry> </variablelist> diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.txt b/Documentation/devicetree/bindings/media/i2c/adv7604.txt index c27cede3bd68..8337f75c75da 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7604.txt +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.txt @@ -1,15 +1,17 @@ -* Analog Devices ADV7604/11 video decoder with HDMI receiver +* Analog Devices ADV7604/11/12 video decoder with HDMI receiver -The ADV7604 and ADV7611 are multiformat video decoders with an integrated HDMI -receiver. The ADV7604 has four multiplexed HDMI inputs and one analog input, -and the ADV7611 has one HDMI input and no analog input. +The ADV7604 and ADV7611/12 are multiformat video decoders with an integrated +HDMI receiver. The ADV7604 has four multiplexed HDMI inputs and one analog +input, and the ADV7611 has one HDMI input and no analog input. The 7612 is +similar to the 7611 but has 2 HDMI inputs. -These device tree bindings support the ADV7611 only at the moment. +These device tree bindings support the ADV7611/12 only at the moment. Required Properties: - compatible: Must contain one of the following - "adi,adv7611" for the ADV7611 + - "adi,adv7612" for the ADV7612 - reg: I2C slave address @@ -22,10 +24,10 @@ port, in accordance with the video interface bindings defined in Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes are numbered as follows. - Port ADV7611 + Port ADV7611 ADV7612 ------------------------------------------------------------ - HDMI 0 - Digital output 1 + HDMI 0 0, 1 + Digital output 1 2 The digital output port node must contain at least one endpoint. @@ -45,6 +47,7 @@ Optional Endpoint Properties: If none of hsync-active, vsync-active and pclk-sample is specified the endpoint will use embedded BT.656 synchronization. + - default-input: Select which input is selected after reset. Example: @@ -58,6 +61,8 @@ Example: #address-cells = <1>; #size-cells = <0>; + default-input = <0>; + port@0 { reg = <0>; }; diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c index c187b9579c21..f27c618de527 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c @@ -343,7 +343,7 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("2ddmac0", &mstp_clks[HWBLK_2DDMAC]), CLKDEV_DEV_ID("sh_fsi.0", &mstp_clks[HWBLK_SPU]), CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]), - CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]), + CLKDEV_DEV_ID("sh-vou", &mstp_clks[HWBLK_VOU]), CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU0]), CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU0]), CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU0]), diff --git a/drivers/media/common/saa7146/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c index be746d1aee9a..3dc6a838ca6f 100644 --- a/drivers/media/common/saa7146/saa7146_hlp.c +++ b/drivers/media/common/saa7146/saa7146_hlp.c @@ -307,7 +307,7 @@ static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field /* simple bubble-sort algorithm with duplicate elimination */ static int sort_and_eliminate(u32* values, int* count) { - int low = 0, high = 0, top = 0, temp = 0; + int low = 0, high = 0, top = 0; int cur = 0, next = 0; /* sanity checks */ @@ -318,11 +318,8 @@ static int sort_and_eliminate(u32* values, int* count) /* bubble sort the first @count items of the array @values */ for( top = *count; top > 0; top--) { for( low = 0, high = 1; high < top; low++, high++) { - if( values[low] > values[high] ) { - temp = values[low]; - values[low] = values[high]; - values[high] = temp; - } + if( values[low] > values[high] ) + swap(values[low], values[high]); } } diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 0d35f5850ff1..5ab90f36a6a6 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -240,7 +240,7 @@ config DVB_SI21XX config DVB_TS2020 tristate "Montage Tehnology TS2020 based tuners" - depends on DVB_CORE + depends on DVB_CORE && I2C select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index a493c0b0b5fe..09a96df170d1 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -25,6 +25,7 @@ #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/slab.h> +#include <linux/of.h> #include <media/v4l2-ioctl.h> #include <linux/videodev2.h> #include <media/v4l2-device.h> @@ -1324,11 +1325,21 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume); #define ADV7180_PM_OPS NULL #endif +#ifdef CONFIG_OF +static const struct of_device_id adv7180_of_id[] = { + { .compatible = "adi,adv7180", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, adv7180_of_id); +#endif + static struct i2c_driver adv7180_driver = { .driver = { .owner = THIS_MODULE, .name = KBUILD_MODNAME, .pm = ADV7180_PM_OPS, + .of_match_table = of_match_ptr(adv7180_of_id), }, .probe = adv7180_probe, .remove = adv7180_remove, diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c index 7c50833e7d17..d27283135490 100644 --- a/drivers/media/i2c/adv7343.c +++ b/drivers/media/i2c/adv7343.c @@ -319,13 +319,6 @@ static const struct v4l2_ctrl_ops adv7343_ctrl_ops = { static const struct v4l2_subdev_core_ops adv7343_core_ops = { .log_status = adv7343_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) diff --git a/drivers/media/i2c/adv7393.c b/drivers/media/i2c/adv7393.c index 558f19154eb9..0215f95c2245 100644 --- a/drivers/media/i2c/adv7393.c +++ b/drivers/media/i2c/adv7393.c @@ -306,13 +306,6 @@ static const struct v4l2_ctrl_ops adv7393_ctrl_ops = { static const struct v4l2_subdev_core_ops adv7393_core_ops = { .log_status = adv7393_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static int adv7393_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 808360fd6539..21b549a8dc74 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -37,6 +37,7 @@ #include <linux/v4l2-dv-timings.h> #include <linux/videodev2.h> #include <linux/workqueue.h> +#include <linux/regmap.h> #include <media/adv7604.h> #include <media/v4l2-ctrls.h> @@ -81,6 +82,7 @@ MODULE_LICENSE("GPL"); enum adv76xx_type { ADV7604, ADV7611, + ADV7612, }; struct adv76xx_reg_seq { @@ -188,6 +190,9 @@ struct adv76xx_state { /* i2c clients */ struct i2c_client *i2c_clients[ADV76XX_PAGE_MAX]; + /* Regmaps */ + struct regmap *regmap[ADV76XX_PAGE_MAX]; + /* controls */ struct v4l2_ctrl *detect_tx_5v_ctrl; struct v4l2_ctrl *analog_sampling_phase_ctrl; @@ -373,66 +378,39 @@ static inline unsigned vtotal(const struct v4l2_bt_timings *t) /* ----------------------------------------------------------------------- */ -static s32 adv_smbus_read_byte_data_check(struct i2c_client *client, - u8 command, bool check) -{ - union i2c_smbus_data data; - - if (!i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_READ, command, - I2C_SMBUS_BYTE_DATA, &data)) - return data.byte; - if (check) - v4l_err(client, "error reading %02x, %02x\n", - client->addr, command); - return -EIO; -} - -static s32 adv_smbus_read_byte_data(struct adv76xx_state *state, - enum adv76xx_page page, u8 command) +static int adv76xx_read_check(struct adv76xx_state *state, + int client_page, u8 reg) { - return adv_smbus_read_byte_data_check(state->i2c_clients[page], - command, true); -} - -static s32 adv_smbus_write_byte_data(struct adv76xx_state *state, - enum adv76xx_page page, u8 command, - u8 value) -{ - struct i2c_client *client = state->i2c_clients[page]; - union i2c_smbus_data data; + struct i2c_client *client = state->i2c_clients[client_page]; int err; - int i; + unsigned int val; - data.byte = value; - for (i = 0; i < 3; i++) { - err = i2c_smbus_xfer(client->adapter, client->addr, - client->flags, - I2C_SMBUS_WRITE, command, - I2C_SMBUS_BYTE_DATA, &data); - if (!err) - break; + err = regmap_read(state->regmap[client_page], reg, &val); + + if (err) { + v4l_err(client, "error reading %02x, %02x\n", + client->addr, reg); + return err; } - if (err < 0) - v4l_err(client, "error writing %02x, %02x, %02x\n", - client->addr, command, value); - return err; + return val; } -static s32 adv_smbus_write_i2c_block_data(struct adv76xx_state *state, - enum adv76xx_page page, u8 command, - unsigned length, const u8 *values) +/* adv76xx_write_block(): Write raw data with a maximum of I2C_SMBUS_BLOCK_MAX + * size to one or more registers. + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +static int adv76xx_write_block(struct adv76xx_state *state, int client_page, + unsigned int init_reg, const void *val, + size_t val_len) { - struct i2c_client *client = state->i2c_clients[page]; - union i2c_smbus_data data; + struct regmap *regmap = state->regmap[client_page]; - if (length > I2C_SMBUS_BLOCK_MAX) - length = I2C_SMBUS_BLOCK_MAX; - data.block[0] = length; - memcpy(data.block + 1, values, length); - return i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_WRITE, command, - I2C_SMBUS_I2C_BLOCK_DATA, &data); + if (val_len > I2C_SMBUS_BLOCK_MAX) + val_len = I2C_SMBUS_BLOCK_MAX; + + return regmap_raw_write(regmap, init_reg, val, val_len); } /* ----------------------------------------------------------------------- */ @@ -441,14 +419,14 @@ static inline int io_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_IO, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_IO, reg); } static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_IO, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_IO], reg, val); } static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -460,71 +438,70 @@ static inline int avlink_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_AVLINK, reg); + return adv76xx_read_check(state, ADV7604_PAGE_AVLINK, reg); } static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_AVLINK, reg, val); + return regmap_write(state->regmap[ADV7604_PAGE_AVLINK], reg, val); } static inline int cec_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CEC, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_CEC, reg); } static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CEC, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_CEC], reg, val); } static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_INFOFRAME, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_INFOFRAME, reg); } static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_INFOFRAME, - reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_INFOFRAME], reg, val); } static inline int afe_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_AFE, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_AFE, reg); } static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_AFE, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_AFE], reg, val); } static inline int rep_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_REP, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_REP, reg); } static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_REP, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_REP], reg, val); } static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -536,28 +513,37 @@ static inline int edid_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_EDID, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_EDID, reg); } static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_EDID, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_EDID], reg, val); } static inline int edid_write_block(struct v4l2_subdev *sd, - unsigned len, const u8 *val) + unsigned int total_len, const u8 *val) { struct adv76xx_state *state = to_state(sd); int err = 0; - int i; + int i = 0; + int len = 0; - v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); + v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", + __func__, total_len); + + while (!err && i < total_len) { + len = (total_len - i) > I2C_SMBUS_BLOCK_MAX ? + I2C_SMBUS_BLOCK_MAX : + (total_len - i); + + err = adv76xx_write_block(state, ADV76XX_PAGE_EDID, + i, val + i, len); + i += len; + } - for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) - err = adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_EDID, - i, I2C_SMBUS_BLOCK_MAX, val + i); return err; } @@ -587,7 +573,7 @@ static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_HDMI, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_HDMI, reg); } static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) @@ -599,7 +585,7 @@ static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_HDMI, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_HDMI], reg, val); } static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -611,14 +597,14 @@ static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_TEST, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_TEST], reg, val); } static inline int cp_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CP, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_CP, reg); } static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) @@ -630,7 +616,7 @@ static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CP, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_CP], reg, val); } static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -642,14 +628,14 @@ static inline int vdp_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_VDP, reg); + return adv76xx_read_check(state, ADV7604_PAGE_VDP, reg); } static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_VDP, reg, val); + return regmap_write(state->regmap[ADV7604_PAGE_VDP], reg, val); } #define ADV76XX_REG(page, offset) (((page) << 8) | (offset)) @@ -660,13 +646,16 @@ static int adv76xx_read_reg(struct v4l2_subdev *sd, unsigned int reg) { struct adv76xx_state *state = to_state(sd); unsigned int page = reg >> 8; + unsigned int val; + int err; if (!(BIT(page) & state->info->page_mask)) return -EINVAL; reg &= 0xff; + err = regmap_read(state->regmap[page], reg, &val); - return adv_smbus_read_byte_data(state, page, reg); + return err ? err : val; } #endif @@ -680,7 +669,7 @@ static int adv76xx_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val) reg &= 0xff; - return adv_smbus_write_byte_data(state, page, reg, val); + return regmap_write(state->regmap[page], reg, val); } static void adv76xx_write_reg_seq(struct v4l2_subdev *sd, @@ -766,6 +755,23 @@ static const struct adv76xx_format_info adv7611_formats[] = { ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, }; +static const struct adv76xx_format_info adv7612_formats[] = { + { MEDIA_BUS_FMT_RGB888_1X24, ADV76XX_OP_CH_SEL_RGB, true, false, + ADV76XX_OP_MODE_SEL_SDR_444 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_2X8, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_2X8, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_UYVY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_VYUY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_1X16, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_1X16, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, +}; + static const struct adv76xx_format_info * adv76xx_format_info(struct adv76xx_state *state, u32 code) { @@ -976,8 +982,8 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ /* IO-map reg. 0x16 and 0x17 should be written in sequence */ - if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_IO, - 0x16, 2, pll)) + if (regmap_raw_write(state->regmap[ADV76XX_PAGE_IO], + 0x16, pll, 2)) v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); /* active video - horizontal timing */ @@ -1028,8 +1034,8 @@ static void adv76xx_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 off offset_buf[3] = offset_c & 0x0ff; /* Registers must be written in this order with no i2c access in between */ - if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_CP, - 0x77, 4, offset_buf)) + if (regmap_raw_write(state->regmap[ADV76XX_PAGE_CP], + 0x77, offset_buf, 4)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); } @@ -1058,8 +1064,8 @@ static void adv76xx_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, gain_buf[3] = ((gain_c & 0x0ff)); /* Registers must be written in this order with no i2c access in between */ - if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_CP, - 0x73, 4, gain_buf)) + if (regmap_raw_write(state->regmap[ADV76XX_PAGE_CP], + 0x73, gain_buf, 4)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); } @@ -1328,7 +1334,7 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, } } - if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, + if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), false, timings)) @@ -2510,6 +2516,11 @@ static void adv7611_setup_irqs(struct v4l2_subdev *sd) io_write(sd, 0x41, 0xd0); /* STDI irq for any change, disable INT2 */ } +static void adv7612_setup_irqs(struct v4l2_subdev *sd) +{ + io_write(sd, 0x41, 0xd0); /* disable INT2 */ +} + static void adv76xx_unregister_clients(struct adv76xx_state *state) { unsigned int i; @@ -2597,6 +2608,19 @@ static const struct adv76xx_reg_seq adv7611_recommended_settings_hdmi[] = { { ADV76XX_REG_SEQ_TERM, 0 }, }; +static const struct adv76xx_reg_seq adv7612_recommended_settings_hdmi[] = { + { ADV76XX_REG(ADV76XX_PAGE_CP, 0x6c), 0x00 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x9b), 0x03 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x6f), 0x08 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x85), 0x1f }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x87), 0x70 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0xda }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x01 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x03), 0x98 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4c), 0x44 }, + { ADV76XX_REG_SEQ_TERM, 0 }, +}; + static const struct adv76xx_chip_info adv76xx_chip_info[] = { [ADV7604] = { .type = ADV7604, @@ -2685,17 +2709,59 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = { .field1_vsync_mask = 0x3fff, .field1_vbackporch_mask = 0x3fff, }, + [ADV7612] = { + .type = ADV7612, + .has_afe = false, + .max_port = ADV7604_PAD_HDMI_PORT_B, + .num_dv_ports = 2, + .edid_enable_reg = 0x74, + .edid_status_reg = 0x76, + .lcf_reg = 0xa3, + .tdms_lock_mask = 0x43, + .cable_det_mask = 0x01, + .fmt_change_digital_mask = 0x03, + .formats = adv7612_formats, + .nformats = ARRAY_SIZE(adv7612_formats), + .set_termination = adv7611_set_termination, + .setup_irqs = adv7612_setup_irqs, + .read_hdmi_pixelclock = adv7611_read_hdmi_pixelclock, + .read_cable_det = adv7611_read_cable_det, + .recommended_settings = { + [1] = adv7612_recommended_settings_hdmi, + }, + .num_recommended_settings = { + [1] = ARRAY_SIZE(adv7612_recommended_settings_hdmi), + }, + .page_mask = BIT(ADV76XX_PAGE_IO) | BIT(ADV76XX_PAGE_CEC) | + BIT(ADV76XX_PAGE_INFOFRAME) | BIT(ADV76XX_PAGE_AFE) | + BIT(ADV76XX_PAGE_REP) | BIT(ADV76XX_PAGE_EDID) | + BIT(ADV76XX_PAGE_HDMI) | BIT(ADV76XX_PAGE_CP), + .linewidth_mask = 0x1fff, + .field0_height_mask = 0x1fff, + .field1_height_mask = 0x1fff, + .hfrontporch_mask = 0x1fff, + .hsync_mask = 0x1fff, + .hbackporch_mask = 0x1fff, + .field0_vfrontporch_mask = 0x3fff, + .field0_vsync_mask = 0x3fff, + .field0_vbackporch_mask = 0x3fff, + .field1_vfrontporch_mask = 0x3fff, + .field1_vsync_mask = 0x3fff, + .field1_vbackporch_mask = 0x3fff, + }, }; static const struct i2c_device_id adv76xx_i2c_id[] = { { "adv7604", (kernel_ulong_t)&adv76xx_chip_info[ADV7604] }, { "adv7611", (kernel_ulong_t)&adv76xx_chip_info[ADV7611] }, + { "adv7612", (kernel_ulong_t)&adv76xx_chip_info[ADV7612] }, { } }; MODULE_DEVICE_TABLE(i2c, adv76xx_i2c_id); static const struct of_device_id adv76xx_of_id[] __maybe_unused = { { .compatible = "adi,adv7611", .data = &adv76xx_chip_info[ADV7611] }, + { .compatible = "adi,adv7612", .data = &adv76xx_chip_info[ADV7612] }, { } }; MODULE_DEVICE_TABLE(of, adv76xx_of_id); @@ -2706,6 +2772,7 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) struct device_node *endpoint; struct device_node *np; unsigned int flags; + u32 v; np = state->i2c_clients[ADV76XX_PAGE_IO]->dev.of_node; @@ -2715,6 +2782,12 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) return -EINVAL; v4l2_of_parse_endpoint(endpoint, &bus_cfg); + + if (!of_property_read_u32(endpoint, "default-input", &v)) + state->pdata.default_input = v; + else + state->pdata.default_input = -1; + of_node_put(endpoint); flags = bus_cfg.bus.parallel.flags; @@ -2753,7 +2826,6 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) /* Hardcode the remaining platform data fields. */ state->pdata.disable_pwrdnb = 0; state->pdata.disable_cable_det_rst = 0; - state->pdata.default_input = -1; state->pdata.blank_data = 1; state->pdata.alt_data_sat = 1; state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0; @@ -2762,6 +2834,148 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) return 0; } +static const struct regmap_config adv76xx_regmap_cnf[] = { + { + .name = "io", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "avlink", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "cec", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "infoframe", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "esdp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "epp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "afe", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "rep", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "edid", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + + { + .name = "hdmi", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "test", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "cp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "vdp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, +}; + +static int configure_regmap(struct adv76xx_state *state, int region) +{ + int err; + + if (!state->i2c_clients[region]) + return -ENODEV; + + state->regmap[region] = + devm_regmap_init_i2c(state->i2c_clients[region], + &adv76xx_regmap_cnf[region]); + + if (IS_ERR(state->regmap[region])) { + err = PTR_ERR(state->regmap[region]); + v4l_err(state->i2c_clients[region], + "Error initializing regmap %d with error %d\n", + region, err); + return -EINVAL; + } + + return 0; +} + +static int configure_regmaps(struct adv76xx_state *state) +{ + int i, err; + + for (i = ADV7604_PAGE_AVLINK ; i < ADV76XX_PAGE_MAX; i++) { + err = configure_regmap(state, i); + if (err && (err != -ENODEV)) + return err; + } + return 0; +} + static int adv76xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -2771,7 +2985,7 @@ static int adv76xx_probe(struct i2c_client *client, struct v4l2_ctrl_handler *hdl; struct v4l2_subdev *sd; unsigned int i; - u16 val; + unsigned int val, val2; int err; /* Check if the adapter supports the needed features */ @@ -2835,26 +3049,57 @@ static int adv76xx_probe(struct i2c_client *client, client->addr); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + /* Configure IO Regmap region */ + err = configure_regmap(state, ADV76XX_PAGE_IO); + + if (err) { + v4l2_err(sd, "Error configuring IO regmap region\n"); + return -ENODEV; + } + /* * Verify that the chip is present. On ADV7604 the RD_INFO register only * identifies the revision, while on ADV7611 it identifies the model as * well. Use the HDMI slave address on ADV7604 and RD_INFO on ADV7611. */ - if (state->info->type == ADV7604) { - val = adv_smbus_read_byte_data_check(client, 0xfb, false); + switch (state->info->type) { + case ADV7604: + err = regmap_read(state->regmap[ADV76XX_PAGE_IO], 0xfb, &val); + if (err) { + v4l2_err(sd, "Error %d reading IO Regmap\n", err); + return -ENODEV; + } if (val != 0x68) { - v4l2_info(sd, "not an adv7604 on address 0x%x\n", + v4l2_err(sd, "not an adv7604 on address 0x%x\n", client->addr << 1); return -ENODEV; } - } else { - val = (adv_smbus_read_byte_data_check(client, 0xea, false) << 8) - | (adv_smbus_read_byte_data_check(client, 0xeb, false) << 0); - if (val != 0x2051) { - v4l2_info(sd, "not an adv7611 on address 0x%x\n", + break; + case ADV7611: + case ADV7612: + err = regmap_read(state->regmap[ADV76XX_PAGE_IO], + 0xea, + &val); + if (err) { + v4l2_err(sd, "Error %d reading IO Regmap\n", err); + return -ENODEV; + } + val2 = val << 8; + err = regmap_read(state->regmap[ADV76XX_PAGE_IO], + 0xeb, + &val); + if (err) { + v4l2_err(sd, "Error %d reading IO Regmap\n", err); + return -ENODEV; + } + val2 |= val; + if ((state->info->type == ADV7611 && val != 0x2051) || + (state->info->type == ADV7612 && val != 0x2041)) { + v4l2_err(sd, "not an adv761x on address 0x%x\n", client->addr << 1); return -ENODEV; } + break; } /* control handlers */ @@ -2941,6 +3186,11 @@ static int adv76xx_probe(struct i2c_client *client, if (err) goto err_work_queues; + /* Configure regmaps */ + err = configure_regmaps(state); + if (err) + goto err_entity; + err = adv76xx_core_init(sd); if (err) goto err_entity; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 4cf79b2422d4..aa0d1a04543b 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1442,7 +1442,7 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, } } - if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, + if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), false, timings)) diff --git a/drivers/media/i2c/cs5345.c b/drivers/media/i2c/cs5345.c index 34b76a9e7515..8cebf9cc8007 100644 --- a/drivers/media/i2c/cs5345.c +++ b/drivers/media/i2c/cs5345.c @@ -132,13 +132,6 @@ static const struct v4l2_ctrl_ops cs5345_ctrl_ops = { static const struct v4l2_subdev_core_ops cs5345_core_ops = { .log_status = cs5345_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = cs5345_g_register, .s_register = cs5345_s_register, diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c index 2960b5a8362a..2240e0a67db1 100644 --- a/drivers/media/i2c/saa6588.c +++ b/drivers/media/i2c/saa6588.c @@ -301,9 +301,7 @@ static void saa6588_i2c_poll(struct saa6588 *s) first and the last of the 3 bytes block. */ - tmp = tmpbuf[2]; - tmpbuf[2] = tmpbuf[0]; - tmpbuf[0] = tmp; + swap(tmpbuf[2], tmpbuf[0]); /* Map 'Invalid block E' to 'Invalid Block' */ if (blocknum == 6) diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index 7d517361e419..c6ba19cf1aa5 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -1204,13 +1204,6 @@ static const struct v4l2_subdev_core_ops saa717x_core_ops = { .g_register = saa717x_g_register, .s_register = saa717x_s_register, #endif - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, .log_status = saa717x_log_status, }; diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c index b62b6ddc4356..229dc76c44a5 100644 --- a/drivers/media/i2c/sr030pc30.c +++ b/drivers/media/i2c/sr030pc30.c @@ -636,13 +636,6 @@ static const struct v4l2_ctrl_ops sr030pc30_ctrl_ops = { static const struct v4l2_subdev_core_ops sr030pc30_core_ops = { .s_power = sr030pc30_s_power, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_pad_ops sr030pc30_pad_ops = { diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index cf93021a6500..d3834a4c48da 100644 --- a/drivers/media/i2c/tda7432.c +++ b/drivers/media/i2c/tda7432.c @@ -331,13 +331,6 @@ static const struct v4l2_ctrl_ops tda7432_ctrl_ops = { static const struct v4l2_subdev_core_ops tda7432_core_ops = { .log_status = tda7432_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_ops tda7432_ops = { diff --git a/drivers/media/i2c/tlv320aic23b.c b/drivers/media/i2c/tlv320aic23b.c index ef87f7b09ea2..0370dd89f1fc 100644 --- a/drivers/media/i2c/tlv320aic23b.c +++ b/drivers/media/i2c/tlv320aic23b.c @@ -122,13 +122,6 @@ static const struct v4l2_ctrl_ops tlv320aic23b_ctrl_ops = { static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = { .log_status = tlv320aic23b_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = { diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 24e47279e30c..a93985a9b070 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -957,16 +957,6 @@ static int tvp514x_set_pad_format(struct v4l2_subdev *sd, return 0; } -static const struct v4l2_subdev_core_ops tvp514x_core_ops = { - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -}; - static const struct v4l2_subdev_video_ops tvp514x_video_ops = { .s_std = tvp514x_s_std, .s_routing = tvp514x_s_routing, @@ -983,7 +973,6 @@ static const struct v4l2_subdev_pad_ops tvp514x_pad_ops = { }; static const struct v4l2_subdev_ops tvp514x_ops = { - .core = &tvp514x_core_ops, .video = &tvp514x_video_ops, .pad = &tvp514x_pad_ops, }; diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 05077cffd235..f617d8b745ee 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -861,13 +861,6 @@ tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cf /* V4L2 core operation handlers */ static const struct v4l2_subdev_core_ops tvp7002_core_ops = { .log_status = tvp7002_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = tvp7002_g_register, .s_register = tvp7002_s_register, diff --git a/drivers/media/i2c/wm8739.c b/drivers/media/i2c/wm8739.c index 3be73f6a40e9..534b0e560317 100644 --- a/drivers/media/i2c/wm8739.c +++ b/drivers/media/i2c/wm8739.c @@ -176,13 +176,6 @@ static const struct v4l2_ctrl_ops wm8739_ctrl_ops = { static const struct v4l2_subdev_core_ops wm8739_core_ops = { .log_status = wm8739_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_audio_ops wm8739_audio_ops = { diff --git a/drivers/media/pci/bt8xx/btcx-risc.c b/drivers/media/pci/bt8xx/btcx-risc.c index 00f0880b6d66..57c7f58c3af2 100644 --- a/drivers/media/pci/bt8xx/btcx-risc.c +++ b/drivers/media/pci/bt8xx/btcx-risc.c @@ -160,7 +160,6 @@ btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int m void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) { - struct v4l2_clip swap; int i,j,n; if (nclips < 2) @@ -168,9 +167,7 @@ btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) for (i = nclips-2; i >= 0; i--) { for (n = 0, j = 0; j <= i; j++) { if (clips[j].c.left > clips[j+1].c.left) { - swap = clips[j]; - clips[j] = clips[j+1]; - clips[j+1] = swap; + swap(clips[j], clips[j + 1]); n++; } } diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig index 3be1b2c3c386..6a1c0089bb62 100644 --- a/drivers/media/pci/cobalt/Kconfig +++ b/drivers/media/pci/cobalt/Kconfig @@ -2,6 +2,7 @@ config VIDEO_COBALT tristate "Cisco Cobalt support" depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER depends on PCI_MSI && MTD_COMPLEX_MAPPINGS && GPIOLIB + depends on SND select I2C_ALGOBIT select VIDEO_ADV7604 select VIDEO_ADV7511 diff --git a/drivers/media/pci/ivtv/ivtv-gpio.c b/drivers/media/pci/ivtv/ivtv-gpio.c index af52def700cc..f752f3993687 100644 --- a/drivers/media/pci/ivtv/ivtv-gpio.c +++ b/drivers/media/pci/ivtv/ivtv-gpio.c @@ -313,13 +313,6 @@ static const struct v4l2_ctrl_ops gpio_ctrl_ops = { static const struct v4l2_subdev_core_ops subdev_core_ops = { .log_status = subdev_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = { diff --git a/drivers/media/pci/smipcie/Kconfig b/drivers/media/pci/smipcie/Kconfig index 21a1583dbd8f..c11c772830c9 100644 --- a/drivers/media/pci/smipcie/Kconfig +++ b/drivers/media/pci/smipcie/Kconfig @@ -7,6 +7,7 @@ config DVB_SMIPCIE select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT + depends on RC_CORE help Support for cards with SMI PCIe bridge: - DVBSky S950 V3 diff --git a/drivers/media/pci/smipcie/Makefile b/drivers/media/pci/smipcie/Makefile index be55481a6e95..013bc3fe4294 100644 --- a/drivers/media/pci/smipcie/Makefile +++ b/drivers/media/pci/smipcie/Makefile @@ -1,3 +1,6 @@ + +smipcie-objs := smipcie-main.o smipcie-ir.o + obj-$(CONFIG_DVB_SMIPCIE) += smipcie.o ccflags-y += -Idrivers/media/tuners diff --git a/drivers/media/pci/smipcie/smipcie-ir.c b/drivers/media/pci/smipcie/smipcie-ir.c new file mode 100644 index 000000000000..d018673c71f6 --- /dev/null +++ b/drivers/media/pci/smipcie/smipcie-ir.c @@ -0,0 +1,232 @@ +/* + * SMI PCIe driver for DVBSky cards. + * + * Copyright (C) 2014 Max nibble <nibble.max@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "smipcie.h" + +static void smi_ir_enableInterrupt(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_write(MSI_INT_ENA_SET, IR_X_INT); +} + +static void smi_ir_disableInterrupt(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_write(MSI_INT_ENA_CLR, IR_X_INT); +} + +static void smi_ir_clearInterrupt(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_write(MSI_INT_STATUS_CLR, IR_X_INT); +} + +static void smi_ir_stop(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_ir_disableInterrupt(ir); + smi_clear(IR_Init_Reg, 0x80); +} + +#define BITS_PER_COMMAND 14 +#define GROUPS_PER_BIT 2 +#define IR_RC5_MIN_BIT 36 +#define IR_RC5_MAX_BIT 52 +static u32 smi_decode_rc5(u8 *pData, u8 size) +{ + u8 index, current_bit, bit_count; + u8 group_array[BITS_PER_COMMAND * GROUPS_PER_BIT + 4]; + u8 group_index = 0; + u32 command = 0xFFFFFFFF; + + group_array[group_index++] = 1; + + for (index = 0; index < size; index++) { + + current_bit = (pData[index] & 0x80) ? 1 : 0; + bit_count = pData[index] & 0x7f; + + if ((current_bit == 1) && (bit_count >= 2*IR_RC5_MAX_BIT + 1)) { + goto process_code; + } else if ((bit_count >= IR_RC5_MIN_BIT) && + (bit_count <= IR_RC5_MAX_BIT)) { + group_array[group_index++] = current_bit; + } else if ((bit_count > IR_RC5_MAX_BIT) && + (bit_count <= 2*IR_RC5_MAX_BIT)) { + group_array[group_index++] = current_bit; + group_array[group_index++] = current_bit; + } else { + goto invalid_timing; + } + if (group_index >= BITS_PER_COMMAND*GROUPS_PER_BIT) + goto process_code; + + if ((group_index == BITS_PER_COMMAND*GROUPS_PER_BIT - 1) + && (group_array[group_index-1] == 0)) { + group_array[group_index++] = 1; + goto process_code; + } + } + +process_code: + if (group_index == (BITS_PER_COMMAND*GROUPS_PER_BIT-1)) + group_array[group_index++] = 1; + + if (group_index == BITS_PER_COMMAND*GROUPS_PER_BIT) { + command = 0; + for (index = 0; index < (BITS_PER_COMMAND*GROUPS_PER_BIT); + index = index + 2) { + if ((group_array[index] == 1) && + (group_array[index+1] == 0)) { + command |= (1 << (BITS_PER_COMMAND - + (index/2) - 1)); + } else if ((group_array[index] == 0) && + (group_array[index+1] == 1)) { + /* */ + } else { + command = 0xFFFFFFFF; + goto invalid_timing; + } + } + } + +invalid_timing: + return command; +} + +static void smi_ir_decode(struct work_struct *work) +{ + struct smi_rc *ir = container_of(work, struct smi_rc, work); + struct smi_dev *dev = ir->dev; + struct rc_dev *rc_dev = ir->rc_dev; + u32 dwIRControl, dwIRData, dwIRCode, scancode; + u8 index, ucIRCount, readLoop, rc5_command, rc5_system, toggle; + + dwIRControl = smi_read(IR_Init_Reg); + if (dwIRControl & rbIRVld) { + ucIRCount = (u8) smi_read(IR_Data_Cnt); + + if (ucIRCount < 4) + goto end_ir_decode; + + readLoop = ucIRCount/4; + if (ucIRCount % 4) + readLoop += 1; + for (index = 0; index < readLoop; index++) { + dwIRData = smi_read(IR_DATA_BUFFER_BASE + (index*4)); + + ir->irData[index*4 + 0] = (u8)(dwIRData); + ir->irData[index*4 + 1] = (u8)(dwIRData >> 8); + ir->irData[index*4 + 2] = (u8)(dwIRData >> 16); + ir->irData[index*4 + 3] = (u8)(dwIRData >> 24); + } + dwIRCode = smi_decode_rc5(ir->irData, ucIRCount); + + if (dwIRCode != 0xFFFFFFFF) { + rc5_command = dwIRCode & 0x3F; + rc5_system = (dwIRCode & 0x7C0) >> 6; + toggle = (dwIRCode & 0x800) ? 1 : 0; + scancode = rc5_system << 8 | rc5_command; + rc_keydown(rc_dev, RC_TYPE_RC5, scancode, toggle); + } + } +end_ir_decode: + smi_set(IR_Init_Reg, 0x04); + smi_ir_enableInterrupt(ir); +} + +/* ir functions call by main driver.*/ +int smi_ir_irq(struct smi_rc *ir, u32 int_status) +{ + int handled = 0; + + if (int_status & IR_X_INT) { + smi_ir_disableInterrupt(ir); + smi_ir_clearInterrupt(ir); + schedule_work(&ir->work); + handled = 1; + } + return handled; +} + +void smi_ir_start(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_write(IR_Idle_Cnt_Low, 0x00140070); + msleep(20); + smi_set(IR_Init_Reg, 0x90); + + smi_ir_enableInterrupt(ir); +} + +int smi_ir_init(struct smi_dev *dev) +{ + int ret; + struct rc_dev *rc_dev; + struct smi_rc *ir = &dev->ir; + + rc_dev = rc_allocate_device(); + if (!rc_dev) + return -ENOMEM; + + /* init input device */ + snprintf(ir->input_name, sizeof(ir->input_name), "IR (%s)", + dev->info->name); + snprintf(ir->input_phys, sizeof(ir->input_phys), "pci-%s/ir0", + pci_name(dev->pci_dev)); + + rc_dev->driver_name = "SMI_PCIe"; + rc_dev->input_phys = ir->input_phys; + rc_dev->input_name = ir->input_name; + rc_dev->input_id.bustype = BUS_PCI; + rc_dev->input_id.version = 1; + rc_dev->input_id.vendor = dev->pci_dev->subsystem_vendor; + rc_dev->input_id.product = dev->pci_dev->subsystem_device; + rc_dev->dev.parent = &dev->pci_dev->dev; + + rc_dev->driver_type = RC_DRIVER_SCANCODE; + rc_dev->map_name = RC_MAP_DVBSKY; + + ir->rc_dev = rc_dev; + ir->dev = dev; + + INIT_WORK(&ir->work, smi_ir_decode); + smi_ir_disableInterrupt(ir); + + ret = rc_register_device(rc_dev); + if (ret) + goto ir_err; + + return 0; +ir_err: + rc_free_device(rc_dev); + return ret; +} + +void smi_ir_exit(struct smi_dev *dev) +{ + struct smi_rc *ir = &dev->ir; + struct rc_dev *rc_dev = ir->rc_dev; + + smi_ir_stop(ir); + rc_unregister_device(rc_dev); + ir->rc_dev = NULL; +} diff --git a/drivers/media/pci/smipcie/smipcie.c b/drivers/media/pci/smipcie/smipcie-main.c index 143fd7899ecd..b039a229b7d2 100644 --- a/drivers/media/pci/smipcie/smipcie.c +++ b/drivers/media/pci/smipcie/smipcie-main.c @@ -468,6 +468,7 @@ static irqreturn_t smi_irq_handler(int irq, void *dev_id) struct smi_dev *dev = dev_id; struct smi_port *port0 = &dev->ts_port[0]; struct smi_port *port1 = &dev->ts_port[1]; + struct smi_rc *ir = &dev->ir; int handled = 0; u32 intr_status = smi_read(MSI_INT_STATUS); @@ -480,6 +481,9 @@ static irqreturn_t smi_irq_handler(int irq, void *dev_id) if (dev->info->ts_1) handled += smi_port_irq(port1, intr_status); + /* ir interrupt.*/ + handled += smi_ir_irq(ir, intr_status); + return IRQ_RETVAL(handled); } @@ -993,6 +997,10 @@ static int smi_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_del_port0_attach; } + ret = smi_ir_init(dev); + if (ret < 0) + goto err_del_port1_attach; + #ifdef CONFIG_PCI_MSI /* to do msi interrupt.???*/ if (pci_msi_enabled()) ret = pci_enable_msi(dev->pci_dev); @@ -1003,10 +1011,13 @@ static int smi_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = request_irq(dev->pci_dev->irq, smi_irq_handler, IRQF_SHARED, "SMI_PCIE", dev); if (ret < 0) - goto err_del_port1_attach; + goto err_del_ir; + smi_ir_start(&dev->ir); return 0; +err_del_ir: + smi_ir_exit(dev); err_del_port1_attach: if (dev->info->ts_1) smi_port_detach(&dev->ts_port[1]); @@ -1039,6 +1050,7 @@ static void smi_remove(struct pci_dev *pdev) if (dev->info->ts_0) smi_port_detach(&dev->ts_port[0]); + smi_ir_exit(dev); smi_i2c_exit(dev); iounmap(dev->lmmio); pci_set_drvdata(pdev, NULL); diff --git a/drivers/media/pci/smipcie/smipcie.h b/drivers/media/pci/smipcie/smipcie.h index 10cdf20f4839..68cdda28fd98 100644 --- a/drivers/media/pci/smipcie/smipcie.h +++ b/drivers/media/pci/smipcie/smipcie.h @@ -234,6 +234,17 @@ struct smi_cfg_info { int fe_1; }; +struct smi_rc { + struct smi_dev *dev; + struct rc_dev *rc_dev; + char input_phys[64]; + char input_name[64]; + struct work_struct work; + u8 irData[256]; + + int users; +}; + struct smi_port { struct smi_dev *dev; int idx; @@ -284,6 +295,9 @@ struct smi_dev { /* i2c */ struct i2c_adapter i2c_bus[2]; struct i2c_algo_bit_data i2c_bit[2]; + + /* ir */ + struct smi_rc ir; }; #define smi_read(reg) readl(dev->lmmio + ((reg)>>2)) @@ -296,4 +310,9 @@ struct smi_dev { #define smi_set(reg, bit) smi_andor((reg), (bit), (bit)) #define smi_clear(reg, bit) smi_andor((reg), (bit), 0) +int smi_ir_irq(struct smi_rc *ir, u32 int_status); +void smi_ir_start(struct smi_rc *ir); +void smi_ir_exit(struct smi_dev *dev); +int smi_ir_init(struct smi_dev *dev); + #endif /* #ifndef _SMI_PCIE_H_ */ diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index 570d119ea18b..f50d07229236 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -134,23 +134,11 @@ static irqreturn_t solo_isr(int irq, void *data) static void free_solo_dev(struct solo_dev *solo_dev) { - struct pci_dev *pdev; - - if (!solo_dev) - return; + struct pci_dev *pdev = solo_dev->pdev; if (solo_dev->dev.parent) device_unregister(&solo_dev->dev); - pdev = solo_dev->pdev; - - /* If we never initialized the PCI device, then nothing else - * below here needs cleanup */ - if (!pdev) { - kfree(solo_dev); - return; - } - if (solo_dev->reg_base) { /* Bring down the sub-devices first */ solo_g723_exit(solo_dev); @@ -164,9 +152,8 @@ static void free_solo_dev(struct solo_dev *solo_dev) /* Now cleanup the PCI device */ solo_irq_off(solo_dev, ~0); + free_irq(pdev->irq, solo_dev); pci_iounmap(pdev, solo_dev->reg_base); - if (pdev->irq) - free_irq(pdev->irq, solo_dev); } pci_release_regions(pdev); @@ -483,7 +470,6 @@ static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) solo_dev->type = id->driver_data; solo_dev->pdev = pdev; - spin_lock_init(&solo_dev->reg_io_lock); ret = v4l2_device_register(&pdev->dev, &solo_dev->v4l2_dev); if (ret) goto fail_probe; diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 7ddc76709caa..4a37a1c51c48 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -48,10 +48,8 @@ /* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page * is broken down to 20 * 48 byte regions (one for each channel possible) * with the rest of the page being dummy data. */ -#define G723_MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX) +#define PERIODS G723_FDMA_PAGES #define G723_INTR_ORDER 4 /* 0 - 4 */ -#define PERIODS_MIN (1 << G723_INTR_ORDER) -#define PERIODS_MAX G723_FDMA_PAGES struct solo_snd_pcm { int on; @@ -130,11 +128,11 @@ static const struct snd_pcm_hardware snd_solo_pcm_hw = { .rate_max = SAMPLERATE, .channels_min = 1, .channels_max = 1, - .buffer_bytes_max = G723_MAX_BUFFER, + .buffer_bytes_max = G723_PERIOD_BYTES * PERIODS, .period_bytes_min = G723_PERIOD_BYTES, .period_bytes_max = G723_PERIOD_BYTES, - .periods_min = PERIODS_MIN, - .periods_max = PERIODS_MAX, + .periods_min = PERIODS, + .periods_max = PERIODS, }; static int snd_solo_pcm_open(struct snd_pcm_substream *ss) @@ -340,7 +338,8 @@ static int solo_snd_pcm_init(struct solo_dev *solo_dev) ret = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), - G723_MAX_BUFFER, G723_MAX_BUFFER); + G723_PERIOD_BYTES * PERIODS, + G723_PERIOD_BYTES * PERIODS); if (ret < 0) return ret; diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h index 1ca54b08b3aa..27423d7f5410 100644 --- a/drivers/media/pci/solo6x10/solo6x10.h +++ b/drivers/media/pci/solo6x10/solo6x10.h @@ -199,7 +199,6 @@ struct solo_dev { int nr_ext; u32 irq_mask; u32 motion_mask; - spinlock_t reg_io_lock; struct v4l2_device v4l2_dev; /* tw28xx accounting */ @@ -281,36 +280,13 @@ struct solo_dev { static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg) { - unsigned long flags; - u32 ret; - u16 val; - - spin_lock_irqsave(&solo_dev->reg_io_lock, flags); - - ret = readl(solo_dev->reg_base + reg); - rmb(); - pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val); - rmb(); - - spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags); - - return ret; + return readl(solo_dev->reg_base + reg); } static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data) { - unsigned long flags; - u16 val; - - spin_lock_irqsave(&solo_dev->reg_io_lock, flags); - writel(data, solo_dev->reg_base + reg); - wmb(); - pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val); - rmb(); - - spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags); } static inline void solo_irq_on(struct solo_dev *dev, u32 mask) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 18d0a871747f..12be830d704f 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -829,14 +829,14 @@ static int isp_pipeline_link_notify(struct media_link *link, u32 flags, int ret; if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && - !(link->flags & MEDIA_LNK_FL_ENABLED)) { + !(flags & MEDIA_LNK_FL_ENABLED)) { /* Powering off entities is assumed to never fail. */ isp_pipeline_pm_power(source, -sink_use); isp_pipeline_pm_power(sink, -source_use); return 0; } - if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && + if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH && (flags & MEDIA_LNK_FL_ENABLED)) { ret = isp_pipeline_pm_power(source, sink_use); @@ -2000,10 +2000,8 @@ static int isp_register_entities(struct isp_device *isp) ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); done: - if (ret < 0) { + if (ret < 0) isp_unregister_entities(isp); - v4l2_async_notifier_unregister(&isp->notifier); - } return ret; } @@ -2423,10 +2421,6 @@ static int isp_probe(struct platform_device *pdev) ret = isp_of_parse_nodes(&pdev->dev, &isp->notifier); if (ret < 0) return ret; - ret = v4l2_async_notifier_register(&isp->v4l2_dev, - &isp->notifier); - if (ret) - return ret; } else { isp->pdata = pdev->dev.platform_data; isp->syscon = syscon_regmap_lookup_by_pdevname("syscon.0"); @@ -2557,18 +2551,27 @@ static int isp_probe(struct platform_device *pdev) if (ret < 0) goto error_iommu; - isp->notifier.bound = isp_subdev_notifier_bound; - isp->notifier.complete = isp_subdev_notifier_complete; - ret = isp_register_entities(isp); if (ret < 0) goto error_modules; + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { + isp->notifier.bound = isp_subdev_notifier_bound; + isp->notifier.complete = isp_subdev_notifier_complete; + + ret = v4l2_async_notifier_register(&isp->v4l2_dev, + &isp->notifier); + if (ret) + goto error_register_entities; + } + isp_core_init(isp, 1); omap3isp_put(isp); return 0; +error_register_entities: + isp_unregister_entities(isp); error_modules: isp_cleanup_modules(isp); error_iommu: diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 8b799bae01b8..fe5c8ab06bd5 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -27,7 +27,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-mediabus.h> -#include <media/videobuf-dma-contig.h> +#include <media/videobuf2-dma-contig.h> /* Mirror addresses are not available for all registers */ #define VOUER 0 @@ -57,31 +57,40 @@ enum sh_vou_status { SH_VOU_RUNNING, }; +#define VOU_MIN_IMAGE_WIDTH 16 #define VOU_MAX_IMAGE_WIDTH 720 -#define VOU_MAX_IMAGE_HEIGHT 576 +#define VOU_MIN_IMAGE_HEIGHT 16 + +struct sh_vou_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + +static inline struct sh_vou_buffer *to_sh_vou_buffer(struct vb2_buffer *vb2) +{ + return container_of(vb2, struct sh_vou_buffer, vb); +} struct sh_vou_device { struct v4l2_device v4l2_dev; struct video_device vdev; - atomic_t use_count; struct sh_vou_pdata *pdata; spinlock_t lock; void __iomem *base; /* State information */ struct v4l2_pix_format pix; struct v4l2_rect rect; - struct list_head queue; + struct list_head buf_list; v4l2_std_id std; int pix_idx; - struct videobuf_buffer *active; + struct vb2_queue queue; + struct vb2_alloc_ctx *alloc_ctx; + struct sh_vou_buffer *active; enum sh_vou_status status; + unsigned sequence; struct mutex fop_lock; }; -struct sh_vou_file { - struct videobuf_queue vbq; -}; - /* Register access routines for sides A, B and mirror addresses */ static void sh_vou_reg_a_write(struct sh_vou_device *vou_dev, unsigned int reg, u32 value) @@ -133,6 +142,7 @@ struct sh_vou_fmt { u32 pfmt; char *desc; unsigned char bpp; + unsigned char bpl; unsigned char rgb; unsigned char yf; unsigned char pkf; @@ -143,6 +153,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_NV12, .bpp = 12, + .bpl = 1, .desc = "YVU420 planar", .yf = 0, .rgb = 0, @@ -150,6 +161,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_NV16, .bpp = 16, + .bpl = 1, .desc = "YVYU planar", .yf = 1, .rgb = 0, @@ -157,6 +169,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_RGB24, .bpp = 24, + .bpl = 3, .desc = "RGB24", .pkf = 2, .rgb = 1, @@ -164,6 +177,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_RGB565, .bpp = 16, + .bpl = 2, .desc = "RGB565", .pkf = 3, .rgb = 1, @@ -171,6 +185,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_RGB565X, .bpp = 16, + .bpl = 2, .desc = "RGB565 byteswapped", .pkf = 3, .rgb = 1, @@ -178,11 +193,11 @@ static struct sh_vou_fmt vou_fmt[] = { }; static void sh_vou_schedule_next(struct sh_vou_device *vou_dev, - struct videobuf_buffer *vb) + struct vb2_buffer *vb) { dma_addr_t addr1, addr2; - addr1 = videobuf_to_dma_contig(vb); + addr1 = vb2_dma_contig_plane_dma_addr(vb, 0); switch (vou_dev->pix.pixelformat) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV16: @@ -196,8 +211,7 @@ static void sh_vou_schedule_next(struct sh_vou_device *vou_dev, sh_vou_reg_m_write(vou_dev, VOUAD2R, addr2); } -static void sh_vou_stream_start(struct sh_vou_device *vou_dev, - struct videobuf_buffer *vb) +static void sh_vou_stream_config(struct sh_vou_device *vou_dev) { unsigned int row_coeff; #ifdef __LITTLE_ENDIAN @@ -224,167 +238,136 @@ static void sh_vou_stream_start(struct sh_vou_device *vou_dev, sh_vou_reg_a_write(vou_dev, VOUSWR, dataswap); sh_vou_reg_ab_write(vou_dev, VOUAIR, vou_dev->pix.width * row_coeff); - sh_vou_schedule_next(vou_dev, vb); -} - -static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - BUG_ON(in_interrupt()); - - /* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */ - videobuf_waiton(vq, vb, 0, 0); - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; } /* Locking: caller holds fop_lock mutex */ -static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) +static int sh_vou_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - - *size = vou_fmt[vou_dev->pix_idx].bpp * vou_dev->pix.width * - vou_dev->pix.height / 8; - - if (*count < 2) - *count = 2; - - /* Taking into account maximum frame size, *count will stay >= 2 */ - if (PAGE_ALIGN(*size) * *count > 4 * 1024 * 1024) - *count = 4 * 1024 * 1024 / PAGE_ALIGN(*size); + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); + struct v4l2_pix_format *pix = &vou_dev->pix; + int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): count=%d, size=%d\n", __func__, - *count, *size); + dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + if (fmt && fmt->fmt.pix.sizeimage < pix->height * bytes_per_line) + return -EINVAL; + *nplanes = 1; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : pix->height * bytes_per_line; + alloc_ctxs[0] = vou_dev->alloc_ctx; return 0; } -/* Locking: caller holds fop_lock mutex */ -static int sh_vou_buf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) +static int sh_vou_buf_prepare(struct vb2_buffer *vb) { - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vb->vb2_queue); struct v4l2_pix_format *pix = &vou_dev->pix; - int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; - int ret; + unsigned bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; + unsigned size = pix->height * bytes_per_line; dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - if (vb->width != pix->width || - vb->height != pix->height || - vb->field != pix->field) { - vb->width = pix->width; - vb->height = pix->height; - vb->field = field; - if (vb->state != VIDEOBUF_NEEDS_INIT) - free_buffer(vq, vb); - } - - vb->size = vb->height * bytes_per_line; - if (vb->baddr && vb->bsize < vb->size) { + if (vb2_plane_size(vb, 0) < size) { /* User buffer too small */ - dev_warn(vq->dev, "User buffer too small: [%zu] @ %lx\n", - vb->bsize, vb->baddr); + dev_warn(vou_dev->v4l2_dev.dev, "buffer too small (%lu < %u)\n", + vb2_plane_size(vb, 0), size); return -EINVAL; } - if (vb->state == VIDEOBUF_NEEDS_INIT) { - ret = videobuf_iolock(vq, vb, NULL); - if (ret < 0) { - dev_warn(vq->dev, "IOLOCK buf-type %d: %d\n", - vb->memory, ret); - return ret; - } - vb->state = VIDEOBUF_PREPARED; - } - - dev_dbg(vou_dev->v4l2_dev.dev, - "%s(): fmt #%d, %u bytes per line, phys %pad, type %d, state %d\n", - __func__, vou_dev->pix_idx, bytes_per_line, - ({ dma_addr_t addr = videobuf_to_dma_contig(vb); &addr; }), - vb->memory, vb->state); - + vb2_set_plane_payload(vb, 0, size); return 0; } /* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */ -static void sh_vou_buf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void sh_vou_buf_queue(struct vb2_buffer *vb) { - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vb->vb2_queue); + struct sh_vou_buffer *shbuf = to_sh_vou_buffer(vb); + unsigned long flags; - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + spin_lock_irqsave(&vou_dev->lock, flags); + list_add_tail(&shbuf->list, &vou_dev->buf_list); + spin_unlock_irqrestore(&vou_dev->lock, flags); +} + +static int sh_vou_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); + struct sh_vou_buffer *buf, *node; + int ret; - vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &vou_dev->queue); - - if (vou_dev->status == SH_VOU_RUNNING) { - return; - } else if (!vou_dev->active) { - vou_dev->active = vb; - /* Start from side A: we use mirror addresses, so, set B */ - sh_vou_reg_a_write(vou_dev, VOURPR, 1); - dev_dbg(vou_dev->v4l2_dev.dev, "%s: first buffer status 0x%x\n", - __func__, sh_vou_reg_a_read(vou_dev, VOUSTR)); - sh_vou_schedule_next(vou_dev, vb); - /* Only activate VOU after the second buffer */ - } else if (vou_dev->active->queue.next == &vb->queue) { - /* Second buffer - initialise register side B */ - sh_vou_reg_a_write(vou_dev, VOURPR, 0); - sh_vou_stream_start(vou_dev, vb); - - /* Register side switching with frame VSYNC */ - sh_vou_reg_a_write(vou_dev, VOURCR, 5); - dev_dbg(vou_dev->v4l2_dev.dev, "%s: second buffer status 0x%x\n", - __func__, sh_vou_reg_a_read(vou_dev, VOUSTR)); - - /* Enable End-of-Frame (VSYNC) interrupts */ - sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004); - /* Two buffers on the queue - activate the hardware */ - - vou_dev->status = SH_VOU_RUNNING; - sh_vou_reg_a_write(vou_dev, VOUER, 0x107); + vou_dev->sequence = 0; + ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, + video, s_stream, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) { + list_for_each_entry_safe(buf, node, &vou_dev->buf_list, list) { + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + list_del(&buf->list); + } + vou_dev->active = NULL; + return ret; } + + buf = list_entry(vou_dev->buf_list.next, struct sh_vou_buffer, list); + + vou_dev->active = buf; + + /* Start from side A: we use mirror addresses, so, set B */ + sh_vou_reg_a_write(vou_dev, VOURPR, 1); + dev_dbg(vou_dev->v4l2_dev.dev, "%s: first buffer status 0x%x\n", + __func__, sh_vou_reg_a_read(vou_dev, VOUSTR)); + sh_vou_schedule_next(vou_dev, &buf->vb); + + buf = list_entry(buf->list.next, struct sh_vou_buffer, list); + + /* Second buffer - initialise register side B */ + sh_vou_reg_a_write(vou_dev, VOURPR, 0); + sh_vou_schedule_next(vou_dev, &buf->vb); + + /* Register side switching with frame VSYNC */ + sh_vou_reg_a_write(vou_dev, VOURCR, 5); + + sh_vou_stream_config(vou_dev); + /* Enable End-of-Frame (VSYNC) interrupts */ + sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004); + + /* Two buffers on the queue - activate the hardware */ + vou_dev->status = SH_VOU_RUNNING; + sh_vou_reg_a_write(vou_dev, VOUER, 0x107); + return 0; } -static void sh_vou_buf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void sh_vou_stop_streaming(struct vb2_queue *vq) { - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); + struct sh_vou_buffer *buf, *node; unsigned long flags; - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - + v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, + video, s_stream, 0); + /* disable output */ + sh_vou_reg_a_set(vou_dev, VOUER, 0, 1); + /* ...but the current frame will complete */ + sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000); + msleep(50); spin_lock_irqsave(&vou_dev->lock, flags); - - if (vou_dev->active == vb) { - /* disable output */ - sh_vou_reg_a_set(vou_dev, VOUER, 0, 1); - /* ...but the current frame will complete */ - sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000); - vou_dev->active = NULL; - } - - if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED)) { - vb->state = VIDEOBUF_ERROR; - list_del(&vb->queue); + list_for_each_entry_safe(buf, node, &vou_dev->buf_list, list) { + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + list_del(&buf->list); } - + vou_dev->active = NULL; spin_unlock_irqrestore(&vou_dev->lock, flags); - - free_buffer(vq, vb); } -static struct videobuf_queue_ops sh_vou_video_qops = { - .buf_setup = sh_vou_buf_setup, - .buf_prepare = sh_vou_buf_prepare, - .buf_queue = sh_vou_buf_queue, - .buf_release = sh_vou_buf_release, +static struct vb2_ops sh_vou_qops = { + .queue_setup = sh_vou_queue_setup, + .buf_prepare = sh_vou_buf_prepare, + .buf_queue = sh_vou_buf_queue, + .start_streaming = sh_vou_start_streaming, + .stop_streaming = sh_vou_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; /* Video IOCTLs */ @@ -396,7 +379,10 @@ static int sh_vou_querycap(struct file *file, void *priv, dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); strlcpy(cap->card, "SuperH VOU", sizeof(cap->card)); - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + strlcpy(cap->driver, "sh-vou", sizeof(cap->driver)); + strlcpy(cap->bus_info, "platform:sh-vou", sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -540,8 +526,10 @@ static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std) img_height_max = 576; /* Image width must be a multiple of 4 */ - v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2, - &geo->in_height, 0, img_height_max, 1, 0); + v4l_bound_align_image(&geo->in_width, + VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 2, + &geo->in_height, + VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0); /* Select scales to come as close as possible to the output image */ for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) { @@ -671,34 +659,19 @@ static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std) vou_scale_v_num[idx_v], vou_scale_v_den[idx_v], best); } -static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) +static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) { struct sh_vou_device *vou_dev = video_drvdata(file); struct v4l2_pix_format *pix = &fmt->fmt.pix; unsigned int img_height_max; int pix_idx; - struct sh_vou_geometry geo; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - /* Revisit: is this the correct code? */ - .format.code = MEDIA_BUS_FMT_YUYV8_2X8, - .format.field = V4L2_FIELD_INTERLACED, - .format.colorspace = V4L2_COLORSPACE_SMPTE170M, - }; - struct v4l2_mbus_framefmt *mbfmt = &format.format; - int ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, - vou_dev->rect.width, vou_dev->rect.height, - pix->width, pix->height); - if (pix->field == V4L2_FIELD_ANY) - pix->field = V4L2_FIELD_NONE; + dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - if (fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || - pix->field != V4L2_FIELD_NONE) - return -EINVAL; + pix->field = V4L2_FIELD_INTERLACED; + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + pix->ycbcr_enc = pix->quantization = 0; for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++) if (vou_fmt[pix_idx].pfmt == pix->pixelformat) @@ -712,9 +685,38 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, else img_height_max = 576; - /* Image width must be a multiple of 4 */ - v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2, - &pix->height, 0, img_height_max, 1, 0); + v4l_bound_align_image(&pix->width, + VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 2, + &pix->height, + VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0); + pix->bytesperline = pix->width * vou_fmt[pix_idx].bpl; + pix->sizeimage = pix->height * ((pix->width * vou_fmt[pix_idx].bpp) >> 3); + + return 0; +} + +static int sh_vou_set_fmt_vid_out(struct sh_vou_device *vou_dev, + struct v4l2_pix_format *pix) +{ + unsigned int img_height_max; + struct sh_vou_geometry geo; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + /* Revisit: is this the correct code? */ + .format.code = MEDIA_BUS_FMT_YUYV8_2X8, + .format.field = V4L2_FIELD_INTERLACED, + .format.colorspace = V4L2_COLORSPACE_SMPTE170M, + }; + struct v4l2_mbus_framefmt *mbfmt = &format.format; + int pix_idx; + int ret; + + if (vb2_is_busy(&vou_dev->queue)) + return -EBUSY; + + for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++) + if (vou_fmt[pix_idx].pfmt == pix->pixelformat) + break; geo.in_width = pix->width; geo.in_height = pix->height; @@ -733,6 +735,11 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, geo.output.width, geo.output.height, mbfmt->width, mbfmt->height); + if (vou_dev->std & V4L2_STD_525_60) + img_height_max = 480; + else + img_height_max = 576; + /* Sanity checks */ if ((unsigned)mbfmt->width > VOU_MAX_IMAGE_WIDTH || (unsigned)mbfmt->height > img_height_max || @@ -765,109 +772,39 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, return 0; } -static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) +static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) { struct sh_vou_device *vou_dev = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int i; + int ret = sh_vou_try_fmt_vid_out(file, priv, fmt); - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - pix->field = V4L2_FIELD_NONE; - - v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 1, - &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0); - - for (i = 0; i < ARRAY_SIZE(vou_fmt); i++) - if (vou_fmt[i].pfmt == pix->pixelformat) - return 0; - - pix->pixelformat = vou_fmt[0].pfmt; - - return 0; + if (ret) + return ret; + return sh_vou_set_fmt_vid_out(vou_dev, &fmt->fmt.pix); } -static int sh_vou_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req) +static int sh_vou_enum_output(struct file *file, void *fh, + struct v4l2_output *a) { struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + if (a->index) return -EINVAL; - - return videobuf_reqbufs(&vou_file->vbq, req); -} - -static int sh_vou_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - return videobuf_querybuf(&vou_file->vbq, b); -} - -static int sh_vou_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - return videobuf_qbuf(&vou_file->vbq, b); + strlcpy(a->name, "Video Out", sizeof(a->name)); + a->type = V4L2_OUTPUT_TYPE_ANALOG; + a->std = vou_dev->vdev.tvnorms; + return 0; } -static int sh_vou_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +static int sh_vou_g_output(struct file *file, void *fh, unsigned int *i) { - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - return videobuf_dqbuf(&vou_file->vbq, b, file->f_flags & O_NONBLOCK); + *i = 0; + return 0; } -static int sh_vou_streamon(struct file *file, void *priv, - enum v4l2_buf_type buftype) +static int sh_vou_s_output(struct file *file, void *fh, unsigned int i) { - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - int ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, - video, s_stream, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) - return ret; - - /* This calls our .buf_queue() (== sh_vou_buf_queue) */ - return videobuf_streamon(&vou_file->vbq); -} - -static int sh_vou_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - /* - * This calls buf_release from host driver's videobuf_queue_ops for all - * remaining buffers. When the last buffer is freed, stop streaming - */ - videobuf_streamoff(&vou_file->vbq); - v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_stream, 0); - - return 0; + return i ? -EINVAL : 0; } static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt) @@ -892,8 +829,11 @@ static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id) dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, std_id); - if (std_id & ~vou_dev->vdev.tvnorms) - return -EINVAL; + if (std_id == vou_dev->std) + return 0; + + if (vb2_is_busy(&vou_dev->queue)) + return -EBUSY; ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_std_output, std_id); @@ -901,13 +841,25 @@ static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id) if (ret < 0 && ret != -ENOIOCTLCMD) return ret; - if (std_id & V4L2_STD_525_60) + vou_dev->rect.top = vou_dev->rect.left = 0; + vou_dev->rect.width = VOU_MAX_IMAGE_WIDTH; + if (std_id & V4L2_STD_525_60) { sh_vou_reg_ab_set(vou_dev, VOUCR, sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29); - else + vou_dev->rect.height = 480; + } else { sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29); + vou_dev->rect.height = 576; + } + vou_dev->pix.width = vou_dev->rect.width; + vou_dev->pix.height = vou_dev->rect.height; + vou_dev->pix.bytesperline = + vou_dev->pix.width * vou_fmt[vou_dev->pix_idx].bpl; + vou_dev->pix.sizeimage = vou_dev->pix.height * + ((vou_dev->pix.width * vou_fmt[vou_dev->pix_idx].bpp) >> 3); vou_dev->std = std_id; + sh_vou_set_fmt_vid_out(vou_dev, &vou_dev->pix); return 0; } @@ -923,24 +875,66 @@ static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } -static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a) +static int sh_vou_log_status(struct file *file, void *priv) { struct sh_vou_device *vou_dev = video_drvdata(file); - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + pr_info("VOUER: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUER)); + pr_info("VOUCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUCR)); + pr_info("VOUSTR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSTR)); + pr_info("VOUVCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUVCR)); + pr_info("VOUISR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUISR)); + pr_info("VOUBCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUBCR)); + pr_info("VOUDPR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDPR)); + pr_info("VOUDSR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDSR)); + pr_info("VOUVPR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUVPR)); + pr_info("VOUIR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUIR)); + pr_info("VOUSRR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSRR)); + pr_info("VOUMSR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUMSR)); + pr_info("VOUHIR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUHIR)); + pr_info("VOUDFR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDFR)); + pr_info("VOUAD1R: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAD1R)); + pr_info("VOUAD2R: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAD2R)); + pr_info("VOUAIR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAIR)); + pr_info("VOUSWR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSWR)); + pr_info("VOURCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOURCR)); + pr_info("VOURPR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOURPR)); + return 0; +} - a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - a->c = vou_dev->rect; +static int sh_vou_g_selection(struct file *file, void *fh, + struct v4l2_selection *sel) +{ + struct sh_vou_device *vou_dev = video_drvdata(file); + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + switch (sel->target) { + case V4L2_SEL_TGT_COMPOSE: + sel->r = vou_dev->rect; + break; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = VOU_MAX_IMAGE_WIDTH; + if (vou_dev->std & V4L2_STD_525_60) + sel->r.height = 480; + else + sel->r.height = 576; + break; + default: + return -EINVAL; + } return 0; } /* Assume a dull encoder, do all the work ourselves. */ -static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) +static int sh_vou_s_selection(struct file *file, void *fh, + struct v4l2_selection *sel) { - struct v4l2_crop a_writable = *a; + struct v4l2_rect *rect = &sel->r; struct sh_vou_device *vou_dev = video_drvdata(file); - struct v4l2_rect *rect = &a_writable.c; struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT}; struct v4l2_pix_format *pix = &vou_dev->pix; struct sh_vou_geometry geo; @@ -954,19 +948,22 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) unsigned int img_height_max; int ret; - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__, - rect->width, rect->height, rect->left, rect->top); - - if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || + sel->target != V4L2_SEL_TGT_COMPOSE) return -EINVAL; + if (vb2_is_busy(&vou_dev->queue)) + return -EBUSY; + if (vou_dev->std & V4L2_STD_525_60) img_height_max = 480; else img_height_max = 576; - v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1, - &rect->height, 0, img_height_max, 1, 0); + v4l_bound_align_image(&rect->width, + VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 1, + &rect->height, + VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0); if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH) rect->left = VOU_MAX_IMAGE_WIDTH - rect->width; @@ -1021,41 +1018,11 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) return 0; } -/* - * Total field: NTSC 858 x 2 * 262/263, PAL 864 x 2 * 312/313, default rectangle - * is the initial register values, height takes the interlaced format into - * account. The actual image can only go up to 720 x 2 * 240, So, VOUVPR can - * actually only meaningfully contain values <= 720 and <= 240 respectively, and - * not <= 864 and <= 312. - */ -static int sh_vou_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *a) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = VOU_MAX_IMAGE_WIDTH; - a->bounds.height = VOU_MAX_IMAGE_HEIGHT; - /* Default = max, set VOUDPR = 0, which is not hardware default */ - a->defrect.left = 0; - a->defrect.top = 0; - a->defrect.width = VOU_MAX_IMAGE_WIDTH; - a->defrect.height = VOU_MAX_IMAGE_HEIGHT; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - static irqreturn_t sh_vou_isr(int irq, void *dev_id) { struct sh_vou_device *vou_dev = dev_id; static unsigned long j; - struct videobuf_buffer *vb; + struct sh_vou_buffer *vb; static int cnt; u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked; u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR); @@ -1068,7 +1035,7 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id) } spin_lock(&vou_dev->lock); - if (!vou_dev->active || list_empty(&vou_dev->queue)) { + if (!vou_dev->active || list_empty(&vou_dev->buf_list)) { if (printk_timed_ratelimit(&j, 500)) dev_warn(vou_dev->v4l2_dev.dev, "IRQ without active buffer: %x!\n", irq_status); @@ -1090,33 +1057,30 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id) sh_vou_reg_a_write(vou_dev, VOUIR, masked); vb = vou_dev->active; - list_del(&vb->queue); - - vb->state = VIDEOBUF_DONE; - v4l2_get_timestamp(&vb->ts); - vb->field_count++; - wake_up(&vb->done); - - if (list_empty(&vou_dev->queue)) { - /* Stop VOU */ - dev_dbg(vou_dev->v4l2_dev.dev, "%s: queue empty after %d\n", - __func__, cnt); - sh_vou_reg_a_set(vou_dev, VOUER, 0, 1); - vou_dev->active = NULL; - vou_dev->status = SH_VOU_INITIALISING; - /* Disable End-of-Frame (VSYNC) interrupts */ - sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000); + if (list_is_singular(&vb->list)) { + /* Keep cycling while no next buffer is available */ + sh_vou_schedule_next(vou_dev, &vb->vb); spin_unlock(&vou_dev->lock); return IRQ_HANDLED; } - vou_dev->active = list_entry(vou_dev->queue.next, - struct videobuf_buffer, queue); + list_del(&vb->list); + + v4l2_get_timestamp(&vb->vb.v4l2_buf.timestamp); + vb->vb.v4l2_buf.sequence = vou_dev->sequence++; + vb->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; + vb2_buffer_done(&vb->vb, VB2_BUF_STATE_DONE); - if (vou_dev->active->queue.next != &vou_dev->queue) { - struct videobuf_buffer *new = list_entry(vou_dev->active->queue.next, - struct videobuf_buffer, queue); - sh_vou_schedule_next(vou_dev, new); + vou_dev->active = list_entry(vou_dev->buf_list.next, + struct sh_vou_buffer, list); + + if (list_is_singular(&vou_dev->buf_list)) { + /* Keep cycling while no next buffer is available */ + sh_vou_schedule_next(vou_dev, &vou_dev->active->vb); + } else { + struct sh_vou_buffer *new = list_entry(vou_dev->active->list.next, + struct sh_vou_buffer, list); + sh_vou_schedule_next(vou_dev, &new->vb); } spin_unlock(&vou_dev->lock); @@ -1156,6 +1120,8 @@ static int sh_vou_hw_init(struct sh_vou_device *vou_dev) /* Default - fixed HSYNC length, can be made configurable is required */ sh_vou_reg_ab_write(vou_dev, VOUMSR, 0x800000); + sh_vou_set_fmt_vid_out(vou_dev, &vou_dev->pix); + return 0; } @@ -1163,96 +1129,47 @@ static int sh_vou_hw_init(struct sh_vou_device *vou_dev) static int sh_vou_open(struct file *file) { struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = kzalloc(sizeof(struct sh_vou_file), - GFP_KERNEL); - - if (!vou_file) - return -ENOMEM; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + int err; - if (mutex_lock_interruptible(&vou_dev->fop_lock)) { - kfree(vou_file); + if (mutex_lock_interruptible(&vou_dev->fop_lock)) return -ERESTARTSYS; - } - if (atomic_inc_return(&vou_dev->use_count) == 1) { - int ret; + + err = v4l2_fh_open(file); + if (err) + goto done_open; + if (v4l2_fh_is_singular_file(file) && + vou_dev->status == SH_VOU_INITIALISING) { /* First open */ - vou_dev->status = SH_VOU_INITIALISING; pm_runtime_get_sync(vou_dev->v4l2_dev.dev); - ret = sh_vou_hw_init(vou_dev); - if (ret < 0) { - atomic_dec(&vou_dev->use_count); + err = sh_vou_hw_init(vou_dev); + if (err < 0) { pm_runtime_put(vou_dev->v4l2_dev.dev); + v4l2_fh_release(file); + } else { vou_dev->status = SH_VOU_IDLE; - mutex_unlock(&vou_dev->fop_lock); - kfree(vou_file); - return ret; } } - - videobuf_queue_dma_contig_init(&vou_file->vbq, &sh_vou_video_qops, - vou_dev->v4l2_dev.dev, &vou_dev->lock, - V4L2_BUF_TYPE_VIDEO_OUTPUT, - V4L2_FIELD_NONE, - sizeof(struct videobuf_buffer), - &vou_dev->vdev, &vou_dev->fop_lock); +done_open: mutex_unlock(&vou_dev->fop_lock); - - file->private_data = vou_file; - - return 0; + return err; } static int sh_vou_release(struct file *file) { struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = file->private_data; + bool is_last; - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - if (!atomic_dec_return(&vou_dev->use_count)) { - mutex_lock(&vou_dev->fop_lock); + mutex_lock(&vou_dev->fop_lock); + is_last = v4l2_fh_is_singular_file(file); + _vb2_fop_release(file, NULL); + if (is_last) { /* Last close */ - vou_dev->status = SH_VOU_IDLE; + vou_dev->status = SH_VOU_INITIALISING; sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101); pm_runtime_put(vou_dev->v4l2_dev.dev); - mutex_unlock(&vou_dev->fop_lock); } - - file->private_data = NULL; - kfree(vou_file); - - return 0; -} - -static int sh_vou_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = file->private_data; - int ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - if (mutex_lock_interruptible(&vou_dev->fop_lock)) - return -ERESTARTSYS; - ret = videobuf_mmap_mapper(&vou_file->vbq, vma); mutex_unlock(&vou_dev->fop_lock); - return ret; -} - -static unsigned int sh_vou_poll(struct file *file, poll_table *wait) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = file->private_data; - unsigned int res; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - mutex_lock(&vou_dev->fop_lock); - res = videobuf_poll_stream(file, &vou_file->vbq, wait); - mutex_unlock(&vou_dev->fop_lock); - return res; + return 0; } /* sh_vou display ioctl operations */ @@ -1262,17 +1179,23 @@ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { .vidioc_g_fmt_vid_out = sh_vou_g_fmt_vid_out, .vidioc_s_fmt_vid_out = sh_vou_s_fmt_vid_out, .vidioc_try_fmt_vid_out = sh_vou_try_fmt_vid_out, - .vidioc_reqbufs = sh_vou_reqbufs, - .vidioc_querybuf = sh_vou_querybuf, - .vidioc_qbuf = sh_vou_qbuf, - .vidioc_dqbuf = sh_vou_dqbuf, - .vidioc_streamon = sh_vou_streamon, - .vidioc_streamoff = sh_vou_streamoff, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_g_output = sh_vou_g_output, + .vidioc_s_output = sh_vou_s_output, + .vidioc_enum_output = sh_vou_enum_output, .vidioc_s_std = sh_vou_s_std, .vidioc_g_std = sh_vou_g_std, - .vidioc_cropcap = sh_vou_cropcap, - .vidioc_g_crop = sh_vou_g_crop, - .vidioc_s_crop = sh_vou_s_crop, + .vidioc_g_selection = sh_vou_g_selection, + .vidioc_s_selection = sh_vou_s_selection, + .vidioc_log_status = sh_vou_log_status, }; static const struct v4l2_file_operations sh_vou_fops = { @@ -1280,8 +1203,9 @@ static const struct v4l2_file_operations sh_vou_fops = { .open = sh_vou_open, .release = sh_vou_release, .unlocked_ioctl = video_ioctl2, - .mmap = sh_vou_mmap, - .poll = sh_vou_poll, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, + .write = vb2_fop_write, }; static const struct video_device sh_vou_video_template = { @@ -1300,8 +1224,9 @@ static int sh_vou_probe(struct platform_device *pdev) struct i2c_adapter *i2c_adap; struct video_device *vdev; struct sh_vou_device *vou_dev; - struct resource *reg_res, *region; + struct resource *reg_res; struct v4l2_subdev *subdev; + struct vb2_queue *q; int irq, ret; reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1312,16 +1237,16 @@ static int sh_vou_probe(struct platform_device *pdev) return -ENODEV; } - vou_dev = kzalloc(sizeof(*vou_dev), GFP_KERNEL); + vou_dev = devm_kzalloc(&pdev->dev, sizeof(*vou_dev), GFP_KERNEL); if (!vou_dev) return -ENOMEM; - INIT_LIST_HEAD(&vou_dev->queue); + INIT_LIST_HEAD(&vou_dev->buf_list); spin_lock_init(&vou_dev->lock); mutex_init(&vou_dev->fop_lock); - atomic_set(&vou_dev->use_count, 0); vou_dev->pdata = vou_pdata; - vou_dev->status = SH_VOU_IDLE; + vou_dev->status = SH_VOU_INITIALISING; + vou_dev->pix_idx = 1; rect = &vou_dev->rect; pix = &vou_dev->pix; @@ -1334,34 +1259,24 @@ static int sh_vou_probe(struct platform_device *pdev) rect->height = 480; pix->width = VOU_MAX_IMAGE_WIDTH; pix->height = 480; - pix->pixelformat = V4L2_PIX_FMT_YVYU; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = VOU_MAX_IMAGE_WIDTH * 2; + pix->pixelformat = V4L2_PIX_FMT_NV16; + pix->field = V4L2_FIELD_INTERLACED; + pix->bytesperline = VOU_MAX_IMAGE_WIDTH; pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - region = request_mem_region(reg_res->start, resource_size(reg_res), - pdev->name); - if (!region) { - dev_err(&pdev->dev, "VOU region already claimed\n"); - ret = -EBUSY; - goto ereqmemreg; - } + vou_dev->base = devm_ioremap_resource(&pdev->dev, reg_res); + if (IS_ERR(vou_dev->base)) + return PTR_ERR(vou_dev->base); - vou_dev->base = ioremap(reg_res->start, resource_size(reg_res)); - if (!vou_dev->base) { - ret = -ENOMEM; - goto emap; - } - - ret = request_irq(irq, sh_vou_isr, 0, "vou", vou_dev); + ret = devm_request_irq(&pdev->dev, irq, sh_vou_isr, 0, "vou", vou_dev); if (ret < 0) - goto ereqirq; + return ret; ret = v4l2_device_register(&pdev->dev, &vou_dev->v4l2_dev); if (ret < 0) { dev_err(&pdev->dev, "Error registering v4l2 device\n"); - goto ev4l2devreg; + return ret; } vdev = &vou_dev->vdev; @@ -1374,6 +1289,30 @@ static int sh_vou_probe(struct platform_device *pdev) video_set_drvdata(vdev, vou_dev); + /* Initialize the vb2 queue */ + q = &vou_dev->queue; + q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; + q->drv_priv = vou_dev; + q->buf_struct_size = sizeof(struct sh_vou_buffer); + q->ops = &sh_vou_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + q->lock = &vou_dev->fop_lock; + ret = vb2_queue_init(q); + if (ret) + goto einitctx; + + vou_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(vou_dev->alloc_ctx)) { + dev_err(&pdev->dev, "Can't allocate buffer context"); + ret = PTR_ERR(vou_dev->alloc_ctx); + goto einitctx; + } + vdev->queue = q; + INIT_LIST_HEAD(&vou_dev->buf_list); + pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); @@ -1405,41 +1344,27 @@ ei2cnd: ereset: i2c_put_adapter(i2c_adap); ei2cgadap: + vb2_dma_contig_cleanup_ctx(vou_dev->alloc_ctx); +einitctx: pm_runtime_disable(&pdev->dev); v4l2_device_unregister(&vou_dev->v4l2_dev); -ev4l2devreg: - free_irq(irq, vou_dev); -ereqirq: - iounmap(vou_dev->base); -emap: - release_mem_region(reg_res->start, resource_size(reg_res)); -ereqmemreg: - kfree(vou_dev); return ret; } static int sh_vou_remove(struct platform_device *pdev) { - int irq = platform_get_irq(pdev, 0); struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); struct sh_vou_device *vou_dev = container_of(v4l2_dev, struct sh_vou_device, v4l2_dev); struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next, struct v4l2_subdev, list); struct i2c_client *client = v4l2_get_subdevdata(sd); - struct resource *reg_res; - if (irq > 0) - free_irq(irq, vou_dev); pm_runtime_disable(&pdev->dev); video_unregister_device(&vou_dev->vdev); i2c_put_adapter(client->adapter); + vb2_dma_contig_cleanup_ctx(vou_dev->alloc_ctx); v4l2_device_unregister(&vou_dev->v4l2_dev); - iounmap(vou_dev->base); - reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (reg_res) - release_mem_region(reg_res->start, resource_size(reg_res)); - kfree(vou_dev); return 0; } diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 287902681164..90701726a06a 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> #include <media/atmel-isi.h> @@ -34,7 +35,6 @@ #define VID_LIMIT_BYTES (16 * 1024 * 1024) #define MIN_FRAME_RATE 15 #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) -#define ISI_DEFAULT_MCLK_FREQ 25000000 /* Frame buffer descriptor */ struct fbd { @@ -82,8 +82,6 @@ struct atmel_isi { struct completion complete; /* ISI peripherial clock */ struct clk *pclk; - /* ISI_MCK, feed to camera sensor to generate pixel clock */ - struct clk *mck; unsigned int irq; struct isi_platform_data pdata; @@ -386,10 +384,13 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) struct atmel_isi *isi = ici->priv; int ret; + pm_runtime_get_sync(ici->v4l2_dev.dev); + /* Reset ISI */ ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); if (ret < 0) { dev_err(icd->parent, "Reset ISI timed out\n"); + pm_runtime_put(ici->v4l2_dev.dev); return ret; } /* Disable all interrupts */ @@ -431,11 +432,9 @@ static void stop_streaming(struct vb2_queue *vq) time_before(jiffies, timeout)) msleep(1); - if (time_after(jiffies, timeout)) { + if (time_after(jiffies, timeout)) dev_err(icd->parent, "Timeout waiting for finishing codec request\n"); - return; - } /* Disable interrupts */ isi_writel(isi, ISI_INTDIS, @@ -445,6 +444,8 @@ static void stop_streaming(struct vb2_queue *vq) ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE); if (ret < 0) dev_err(icd->parent, "Disable ISI timed out\n"); + + pm_runtime_put(ici->v4l2_dev.dev); } static struct vb2_ops isi_video_qops = { @@ -516,7 +517,13 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, if (mf->code != xlate->code) return -EINVAL; + /* Enable PM and peripheral clock before operate isi registers */ + pm_runtime_get_sync(ici->v4l2_dev.dev); + ret = configure_geometry(isi, pix->width, pix->height, xlate->code); + + pm_runtime_put(ici->v4l2_dev.dev); + if (ret < 0) return ret; @@ -730,37 +737,6 @@ static void isi_camera_remove_device(struct soc_camera_device *icd) icd->devnum); } -/* Called with .host_lock held */ -static int isi_camera_clock_start(struct soc_camera_host *ici) -{ - struct atmel_isi *isi = ici->priv; - int ret; - - ret = clk_prepare_enable(isi->pclk); - if (ret) - return ret; - - if (!IS_ERR(isi->mck)) { - ret = clk_prepare_enable(isi->mck); - if (ret) { - clk_disable_unprepare(isi->pclk); - return ret; - } - } - - return 0; -} - -/* Called with .host_lock held */ -static void isi_camera_clock_stop(struct soc_camera_host *ici) -{ - struct atmel_isi *isi = ici->priv; - - if (!IS_ERR(isi->mck)) - clk_disable_unprepare(isi->mck); - clk_disable_unprepare(isi->pclk); -} - static unsigned int isi_camera_poll(struct file *file, poll_table *pt) { struct soc_camera_device *icd = file->private_data; @@ -855,9 +831,14 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd) cfg1 |= ISI_CFG1_THMASK_BEATS_16; + /* Enable PM and peripheral clock before operate isi registers */ + pm_runtime_get_sync(ici->v4l2_dev.dev); + isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); isi_writel(isi, ISI_CFG1, cfg1); + pm_runtime_put(ici->v4l2_dev.dev); + return 0; } @@ -865,8 +846,6 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = { .owner = THIS_MODULE, .add = isi_camera_add_device, .remove = isi_camera_remove_device, - .clock_start = isi_camera_clock_start, - .clock_stop = isi_camera_clock_stop, .set_fmt = isi_camera_set_fmt, .try_fmt = isi_camera_try_fmt, .get_formats = isi_camera_get_formats, @@ -889,6 +868,7 @@ static int atmel_isi_remove(struct platform_device *pdev) sizeof(struct fbd) * MAX_BUFFER_NUM, isi->p_fb_descriptors, isi->fb_descriptors_phys); + pm_runtime_disable(&pdev->dev); return 0; } @@ -902,7 +882,6 @@ static int atmel_isi_probe_dt(struct atmel_isi *isi, /* Default settings for ISI */ isi->pdata.full_mode = 1; - isi->pdata.mck_hz = ISI_DEFAULT_MCLK_FREQ; isi->pdata.frate = ISI_CFG1_FRATE_CAPTURE_ALL; np = of_graph_get_next_endpoint(np, NULL); @@ -978,21 +957,6 @@ static int atmel_isi_probe(struct platform_device *pdev) INIT_LIST_HEAD(&isi->video_buffer_list); INIT_LIST_HEAD(&isi->dma_desc_head); - /* ISI_MCK is the sensor master clock. It should be handled by the - * sensor driver directly, as the ISI has no use for that clock. Make - * the clock optional here while platforms transition to the correct - * model. - */ - isi->mck = devm_clk_get(dev, "isi_mck"); - if (!IS_ERR(isi->mck)) { - /* Set ISI_MCK's frequency, it should be faster than pixel - * clock. - */ - ret = clk_set_rate(isi->mck, isi->pdata.mck_hz); - if (ret < 0) - return ret; - } - isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, sizeof(struct fbd) * MAX_BUFFER_NUM, &isi->fb_descriptors_phys, @@ -1027,8 +991,6 @@ static int atmel_isi_probe(struct platform_device *pdev) if (isi->pdata.data_width_flags & ISI_DATAWIDTH_10) isi->width_flags |= 1 << 9; - isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); - irq = platform_get_irq(pdev, 0); if (IS_ERR_VALUE(irq)) { ret = irq; @@ -1049,6 +1011,9 @@ static int atmel_isi_probe(struct platform_device *pdev) soc_host->v4l2_dev.dev = &pdev->dev; soc_host->nr = pdev->id; + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + if (isi->pdata.asd_sizes) { soc_host->asd = isi->pdata.asd; soc_host->asd_sizes = isi->pdata.asd_sizes; @@ -1062,6 +1027,7 @@ static int atmel_isi_probe(struct platform_device *pdev) return 0; err_register_soc_camera_host: + pm_runtime_disable(&pdev->dev); err_req_irq: err_ioremap: vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); @@ -1074,6 +1040,30 @@ err_alloc_ctx: return ret; } +static int atmel_isi_runtime_suspend(struct device *dev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(dev); + struct atmel_isi *isi = container_of(soc_host, + struct atmel_isi, soc_host); + + clk_disable_unprepare(isi->pclk); + + return 0; +} +static int atmel_isi_runtime_resume(struct device *dev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(dev); + struct atmel_isi *isi = container_of(soc_host, + struct atmel_isi, soc_host); + + return clk_prepare_enable(isi->pclk); +} + +static const struct dev_pm_ops atmel_isi_dev_pm_ops = { + SET_RUNTIME_PM_OPS(atmel_isi_runtime_suspend, + atmel_isi_runtime_resume, NULL) +}; + static const struct of_device_id atmel_isi_of_match[] = { { .compatible = "atmel,at91sam9g45-isi" }, { } @@ -1085,6 +1075,7 @@ static struct platform_driver atmel_isi_driver = { .driver = { .name = "atmel_isi", .of_match_table = of_match_ptr(atmel_isi_of_match), + .pm = &atmel_isi_dev_pm_ops, }, }; diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index c4268d1b2f82..ed0b8788a66f 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1627,7 +1627,7 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) h_freq = (u32)bt->pixelclock / total_h_pixel; if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) { - if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, + if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, bt->width, bt->polarities, bt->interlaced, timings)) return true; } diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 913485a90e97..4e61886384e3 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -1,7 +1,7 @@ /* * vsp1_drv.c -- R-Car VSP1 Driver * - * Copyright (C) 2013-2014 Renesas Electronics Corporation + * Copyright (C) 2013-2015 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * @@ -403,7 +403,10 @@ static int vsp1_pm_suspend(struct device *dev) if (vsp1->ref_count == 0) return 0; + vsp1_pipelines_suspend(vsp1); + clk_disable_unprepare(vsp1->clock); + return 0; } @@ -413,10 +416,14 @@ static int vsp1_pm_resume(struct device *dev) WARN_ON(mutex_is_locked(&vsp1->lock)); - if (vsp1->ref_count) + if (vsp1->ref_count == 0) return 0; - return clk_prepare_enable(vsp1->clock); + clk_prepare_enable(vsp1->clock); + + vsp1_pipelines_resume(vsp1); + + return 0; } #endif diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index da3c573e1efc..25b48738b147 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -238,7 +238,7 @@ #define VI6_WPF_SZCLIP_EN (1 << 28) #define VI6_WPF_SZCLIP_OFST_MASK (0xff << 16) #define VI6_WPF_SZCLIP_OFST_SHIFT 16 -#define VI6_WPF_SZCLIP_SIZE_MASK (0x1fff << 0) +#define VI6_WPF_SZCLIP_SIZE_MASK (0xfff << 0) #define VI6_WPF_SZCLIP_SIZE_SHIFT 0 #define VI6_WPF_OUTFMT 0x100c @@ -304,9 +304,9 @@ #define VI6_DPR_HST_ROUTE 0x2044 #define VI6_DPR_HSI_ROUTE 0x2048 #define VI6_DPR_BRU_ROUTE 0x204c -#define VI6_DPR_ROUTE_FXA_MASK (0xff << 8) +#define VI6_DPR_ROUTE_FXA_MASK (0xff << 16) #define VI6_DPR_ROUTE_FXA_SHIFT 16 -#define VI6_DPR_ROUTE_FP_MASK (0xff << 8) +#define VI6_DPR_ROUTE_FP_MASK (0x3f << 8) #define VI6_DPR_ROUTE_FP_SHIFT 8 #define VI6_DPR_ROUTE_RT_MASK (0x3f << 0) #define VI6_DPR_ROUTE_RT_SHIFT 0 diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index fa71f4695e16..9688c219b30e 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c @@ -197,6 +197,17 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, */ format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK, sel->which); + + /* Restrict the crop rectangle coordinates to multiples of 2 to avoid + * shifting the color plane. + */ + if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { + sel->r.left = ALIGN(sel->r.left, 2); + sel->r.top = ALIGN(sel->r.top, 2); + sel->r.width = round_down(sel->r.width, 2); + sel->r.height = round_down(sel->r.height, 2); + } + sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); if (rwpf->entity.type == VSP1_ENTITY_WPF) { diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index d91f19a9e1c1..770e08dc03f1 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -1,7 +1,7 @@ /* * vsp1_video.c -- R-Car VSP1 Video Node * - * Copyright (C) 2013-2014 Renesas Electronics Corporation + * Copyright (C) 2013-2015 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * @@ -514,6 +514,18 @@ static void vsp1_pipeline_run(struct vsp1_pipeline *pipe) pipe->buffers_ready = 0; } +static bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) +{ + unsigned long flags; + bool stopped; + + spin_lock_irqsave(&pipe->irqlock, flags); + stopped = pipe->state == VSP1_PIPELINE_STOPPED, + spin_unlock_irqrestore(&pipe->irqlock, flags); + + return stopped; +} + static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) { struct vsp1_entity *entity; @@ -525,7 +537,7 @@ static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) pipe->state = VSP1_PIPELINE_STOPPING; spin_unlock_irqrestore(&pipe->irqlock, flags); - ret = wait_event_timeout(pipe->wq, pipe->state == VSP1_PIPELINE_STOPPED, + ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe), msecs_to_jiffies(500)); ret = ret == 0 ? -ETIMEDOUT : 0; @@ -703,6 +715,73 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, } } +void vsp1_pipelines_suspend(struct vsp1_device *vsp1) +{ + unsigned long flags; + unsigned int i; + int ret; + + /* To avoid increasing the system suspend time needlessly, loop over the + * pipelines twice, first to set them all to the stopping state, and then + * to wait for the stop to complete. + */ + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { + struct vsp1_rwpf *wpf = vsp1->wpf[i]; + struct vsp1_pipeline *pipe; + + if (wpf == NULL) + continue; + + pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); + if (pipe == NULL) + continue; + + spin_lock_irqsave(&pipe->irqlock, flags); + if (pipe->state == VSP1_PIPELINE_RUNNING) + pipe->state = VSP1_PIPELINE_STOPPING; + spin_unlock_irqrestore(&pipe->irqlock, flags); + } + + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { + struct vsp1_rwpf *wpf = vsp1->wpf[i]; + struct vsp1_pipeline *pipe; + + if (wpf == NULL) + continue; + + pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); + if (pipe == NULL) + continue; + + ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe), + msecs_to_jiffies(500)); + if (ret == 0) + dev_warn(vsp1->dev, "pipeline %u stop timeout\n", + wpf->entity.index); + } +} + +void vsp1_pipelines_resume(struct vsp1_device *vsp1) +{ + unsigned int i; + + /* Resume pipeline all running pipelines. */ + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { + struct vsp1_rwpf *wpf = vsp1->wpf[i]; + struct vsp1_pipeline *pipe; + + if (wpf == NULL) + continue; + + pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); + if (pipe == NULL) + continue; + + if (vsp1_pipeline_ready(pipe)) + vsp1_pipeline_run(pipe); + } +} + /* ----------------------------------------------------------------------------- * videobuf2 Queue Operations */ diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h index fd2851a82e00..0887a4d2742c 100644 --- a/drivers/media/platform/vsp1/vsp1_video.h +++ b/drivers/media/platform/vsp1/vsp1_video.h @@ -1,7 +1,7 @@ /* * vsp1_video.h -- R-Car VSP1 Video Node * - * Copyright (C) 2013-2014 Renesas Electronics Corporation + * Copyright (C) 2013-2015 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * @@ -149,4 +149,7 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, struct vsp1_entity *input, unsigned int alpha); +void vsp1_pipelines_suspend(struct vsp1_device *vsp1); +void vsp1_pipelines_resume(struct vsp1_device *vsp1); + #endif /* __VSP1_VIDEO_H__ */ diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c index ec805b09c608..183e92719140 100644 --- a/drivers/media/radio/saa7706h.c +++ b/drivers/media/radio/saa7706h.c @@ -336,19 +336,7 @@ static const struct v4l2_ctrl_ops saa7706h_ctrl_ops = { .s_ctrl = saa7706h_s_ctrl, }; -static const struct v4l2_subdev_core_ops saa7706h_core_ops = { - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -}; - -static const struct v4l2_subdev_ops saa7706h_ops = { - .core = &saa7706h_core_ops, -}; +static const struct v4l2_subdev_ops empty_ops = {}; /* * Generic i2c probe @@ -373,7 +361,7 @@ static int saa7706h_probe(struct i2c_client *client, if (state == NULL) return -ENOMEM; sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &saa7706h_ops); + v4l2_i2c_subdev_init(sd, client, &empty_ops); v4l2_ctrl_handler_init(&state->hdl, 4); v4l2_ctrl_new_std(&state->hdl, &saa7706h_ctrl_ops, diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 704397f3c106..ebc73b034249 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -689,7 +689,6 @@ static void fm_rx_update_af_cache(struct fmdev *fmdev, u8 af) static void fm_rdsparse_swapbytes(struct fmdev *fmdev, struct fm_rdsdata_format *rds_format) { - u8 byte1; u8 index = 0; u8 *rds_buff; @@ -701,9 +700,7 @@ static void fm_rdsparse_swapbytes(struct fmdev *fmdev, if (fmdev->asci_id != 0x6350) { rds_buff = &rds_format->data.groupdatabuff.buff[0]; while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) { - byte1 = rds_buff[index]; - rds_buff[index] = rds_buff[index + 1]; - rds_buff[index + 1] = byte1; + swap(rds_buff[index], rds_buff[index + 1]); index += 2; } } diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index ddfab256b9a5..b6e13116c6f5 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -371,21 +371,21 @@ config RC_ST tristate "ST remote control receiver" depends on RC_CORE depends on ARCH_STI || COMPILE_TEST - help - Say Y here if you want support for ST remote control driver - which allows both IR and UHF RX. - The driver passes raw pulse and space information to the LIRC decoder. + ---help--- + Say Y here if you want support for ST remote control driver + which allows both IR and UHF RX. + The driver passes raw pulse and space information to the LIRC decoder. - If you're not sure, select N here. + If you're not sure, select N here. config IR_SUNXI - tristate "SUNXI IR remote control" - depends on RC_CORE - depends on ARCH_SUNXI || COMPILE_TEST - ---help--- - Say Y if you want to use sunXi internal IR Controller - - To compile this driver as a module, choose M here: the module will - be called sunxi-ir. + tristate "SUNXI IR remote control" + depends on RC_CORE + depends on ARCH_SUNXI || COMPILE_TEST + ---help--- + Say Y if you want to use sunXi internal IR Controller + + To compile this driver as a module, choose M here: the module will + be called sunxi-ir. endif #RC_DEVICES diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 98893a8332c7..a32659fcd266 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -35,9 +35,6 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) struct lirc_codec *lirc = &dev->raw->lirc; int sample; - if (!(dev->enabled_protocols & RC_BIT_LIRC)) - return 0; - if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf) return -EINVAL; @@ -424,7 +421,7 @@ static int ir_lirc_unregister(struct rc_dev *dev) } static struct ir_raw_handler lirc_handler = { - .protocols = RC_BIT_LIRC, + .protocols = 0, .decode = ir_lirc_decode, .raw_register = ir_lirc_register, .raw_unregister = ir_lirc_unregister, diff --git a/drivers/media/rc/keymaps/rc-lirc.c b/drivers/media/rc/keymaps/rc-lirc.c index fbf08fa6f46e..e172f5db5803 100644 --- a/drivers/media/rc/keymaps/rc-lirc.c +++ b/drivers/media/rc/keymaps/rc-lirc.c @@ -20,7 +20,7 @@ static struct rc_map_list lirc_map = { .map = { .scan = lirc, .size = ARRAY_SIZE(lirc), - .rc_type = RC_TYPE_LIRC, + .rc_type = RC_TYPE_OTHER, .name = RC_MAP_LIRC, } }; diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c index 51f18bb50a37..2b0027c41332 100644 --- a/drivers/media/rc/keymaps/rc-lme2510.c +++ b/drivers/media/rc/keymaps/rc-lme2510.c @@ -15,74 +15,74 @@ static struct rc_map_table lme2510_rc[] = { /* Type 1 - 26 buttons */ - { 0x10ed45, KEY_0 }, - { 0x10ed5f, KEY_1 }, - { 0x10ed50, KEY_2 }, - { 0x10ed5d, KEY_3 }, - { 0x10ed41, KEY_4 }, - { 0x10ed0a, KEY_5 }, - { 0x10ed42, KEY_6 }, - { 0x10ed47, KEY_7 }, - { 0x10ed49, KEY_8 }, - { 0x10ed05, KEY_9 }, - { 0x10ed43, KEY_POWER }, - { 0x10ed46, KEY_SUBTITLE }, - { 0x10ed06, KEY_PAUSE }, - { 0x10ed03, KEY_MEDIA_REPEAT}, - { 0x10ed02, KEY_PAUSE }, - { 0x10ed5e, KEY_VOLUMEUP }, - { 0x10ed5c, KEY_VOLUMEDOWN }, - { 0x10ed09, KEY_CHANNELUP }, - { 0x10ed1a, KEY_CHANNELDOWN }, - { 0x10ed1e, KEY_PLAY }, - { 0x10ed1b, KEY_ZOOM }, - { 0x10ed59, KEY_MUTE }, - { 0x10ed5a, KEY_TV }, - { 0x10ed18, KEY_RECORD }, - { 0x10ed07, KEY_EPG }, - { 0x10ed01, KEY_STOP }, + { 0xef12ba45, KEY_0 }, + { 0xef12a05f, KEY_1 }, + { 0xef12af50, KEY_2 }, + { 0xef12a25d, KEY_3 }, + { 0xef12be41, KEY_4 }, + { 0xef12f50a, KEY_5 }, + { 0xef12bd42, KEY_6 }, + { 0xef12b847, KEY_7 }, + { 0xef12b649, KEY_8 }, + { 0xef12fa05, KEY_9 }, + { 0xef12bc43, KEY_POWER }, + { 0xef12b946, KEY_SUBTITLE }, + { 0xef12f906, KEY_PAUSE }, + { 0xef12fc03, KEY_MEDIA_REPEAT}, + { 0xef12fd02, KEY_PAUSE }, + { 0xef12a15e, KEY_VOLUMEUP }, + { 0xef12a35c, KEY_VOLUMEDOWN }, + { 0xef12f609, KEY_CHANNELUP }, + { 0xef12e51a, KEY_CHANNELDOWN }, + { 0xef12e11e, KEY_PLAY }, + { 0xef12e41b, KEY_ZOOM }, + { 0xef12a659, KEY_MUTE }, + { 0xef12a55a, KEY_TV }, + { 0xef12e718, KEY_RECORD }, + { 0xef12f807, KEY_EPG }, + { 0xef12fe01, KEY_STOP }, /* Type 2 - 20 buttons */ - { 0xbf15, KEY_0 }, - { 0xbf08, KEY_1 }, - { 0xbf09, KEY_2 }, - { 0xbf0a, KEY_3 }, - { 0xbf0c, KEY_4 }, - { 0xbf0d, KEY_5 }, - { 0xbf0e, KEY_6 }, - { 0xbf10, KEY_7 }, - { 0xbf11, KEY_8 }, - { 0xbf12, KEY_9 }, - { 0xbf00, KEY_POWER }, - { 0xbf04, KEY_MEDIA_REPEAT}, /* Recall */ - { 0xbf1a, KEY_PAUSE }, /* Timeshift */ - { 0xbf02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ - { 0xbf06, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ - { 0xbf01, KEY_CHANNELUP }, - { 0xbf05, KEY_CHANNELDOWN }, - { 0xbf14, KEY_ZOOM }, - { 0xbf18, KEY_RECORD }, - { 0xbf16, KEY_STOP }, + { 0xff40ea15, KEY_0 }, + { 0xff40f708, KEY_1 }, + { 0xff40f609, KEY_2 }, + { 0xff40f50a, KEY_3 }, + { 0xff40f30c, KEY_4 }, + { 0xff40f20d, KEY_5 }, + { 0xff40f10e, KEY_6 }, + { 0xff40ef10, KEY_7 }, + { 0xff40ee11, KEY_8 }, + { 0xff40ed12, KEY_9 }, + { 0xff40ff00, KEY_POWER }, + { 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */ + { 0xff40e51a, KEY_PAUSE }, /* Timeshift */ + { 0xff40fd02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ + { 0xff40f906, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ + { 0xff40fe01, KEY_CHANNELUP }, + { 0xff40fa05, KEY_CHANNELDOWN }, + { 0xff40eb14, KEY_ZOOM }, + { 0xff40e718, KEY_RECORD }, + { 0xff40e916, KEY_STOP }, /* Type 3 - 20 buttons */ - { 0x1c, KEY_0 }, - { 0x07, KEY_1 }, - { 0x15, KEY_2 }, - { 0x09, KEY_3 }, - { 0x16, KEY_4 }, - { 0x19, KEY_5 }, - { 0x0d, KEY_6 }, - { 0x0c, KEY_7 }, - { 0x18, KEY_8 }, - { 0x5e, KEY_9 }, - { 0x45, KEY_POWER }, - { 0x44, KEY_MEDIA_REPEAT}, /* Recall */ - { 0x4a, KEY_PAUSE }, /* Timeshift */ - { 0x47, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ - { 0x43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ - { 0x46, KEY_CHANNELUP }, - { 0x40, KEY_CHANNELDOWN }, - { 0x08, KEY_ZOOM }, - { 0x42, KEY_RECORD }, - { 0x5a, KEY_STOP }, + { 0xff00e31c, KEY_0 }, + { 0xff00f807, KEY_1 }, + { 0xff00ea15, KEY_2 }, + { 0xff00f609, KEY_3 }, + { 0xff00e916, KEY_4 }, + { 0xff00e619, KEY_5 }, + { 0xff00f20d, KEY_6 }, + { 0xff00f30c, KEY_7 }, + { 0xff00e718, KEY_8 }, + { 0xff00a15e, KEY_9 }, + { 0xff00ba45, KEY_POWER }, + { 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */ + { 0xff00b54a, KEY_PAUSE }, /* Timeshift */ + { 0xff00b847, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ + { 0xff00bc43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ + { 0xff00b946, KEY_CHANNELUP }, + { 0xff00bf40, KEY_CHANNELDOWN }, + { 0xff00f708, KEY_ZOOM }, + { 0xff00bd42, KEY_RECORD }, + { 0xff00a55a, KEY_STOP }, }; static struct rc_map_list lme2510_map = { diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index b9e4645c731c..1068f2ba56c6 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -406,7 +406,7 @@ int ir_raw_event_register(struct rc_dev *dev) spin_lock_init(&dev->raw->lock); dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw, - "rc%ld", dev->devno); + "rc%u", dev->minor); if (IS_ERR(dev->raw->thread)) { rc = PTR_ERR(dev->raw->thread); diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 9d015db65280..c80816561181 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -18,17 +18,15 @@ #include <linux/input.h> #include <linux/leds.h> #include <linux/slab.h> +#include <linux/idr.h> #include <linux/device.h> #include <linux/module.h> #include "rc-core-priv.h" -/* Bitmap to store allocated device numbers from 0 to IRRCV_NUM_DEVICES - 1 */ -#define IRRCV_NUM_DEVICES 256 -static DECLARE_BITMAP(ir_core_dev_number, IRRCV_NUM_DEVICES); - /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */ #define IR_TAB_MIN_SIZE 256 #define IR_TAB_MAX_SIZE 8192 +#define RC_DEV_MAX 256 /* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */ #define IR_KEYPRESS_TIMEOUT 250 @@ -38,6 +36,9 @@ static LIST_HEAD(rc_map_list); static DEFINE_SPINLOCK(rc_map_lock); static struct led_trigger *led_feedback; +/* Used to keep track of rc devices */ +static DEFINE_IDA(rc_ida); + static struct rc_map_list *seek_rc_map(const char *name) { struct rc_map_list *map = NULL; @@ -799,7 +800,6 @@ static struct { { RC_BIT_SANYO, "sanyo" }, { RC_BIT_SHARP, "sharp" }, { RC_BIT_MCE_KBD, "mce_kbd" }, - { RC_BIT_LIRC, "lirc" }, { RC_BIT_XMP, "xmp" }, }; @@ -884,6 +884,9 @@ static ssize_t show_protocols(struct device *device, allowed &= ~proto_names[i].type; } + if (dev->driver_type == RC_DRIVER_IR_RAW) + tmp += sprintf(tmp, "[lirc] "); + if (tmp != buf) tmp--; *tmp = '\n'; @@ -935,8 +938,12 @@ static int parse_protocol_change(u64 *protocols, const char *buf) } if (i == ARRAY_SIZE(proto_names)) { - IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); - return -EINVAL; + if (!strcasecmp(tmp, "lirc")) + mask = 0; + else { + IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); + return -EINVAL; + } } count++; @@ -1193,9 +1200,6 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct rc_dev *dev = to_rc_dev(device); - if (!dev || !dev->input_dev) - return -ENODEV; - if (dev->rc_map.name) ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); if (dev->driver_name) @@ -1314,7 +1318,9 @@ int rc_register_device(struct rc_dev *dev) static bool raw_init = false; /* raw decoders loaded? */ struct rc_map *rc_map; const char *path; - int rc, devno, attr = 0; + int attr = 0; + int minor; + int rc; if (!dev || !dev->map_name) return -EINVAL; @@ -1334,13 +1340,13 @@ int rc_register_device(struct rc_dev *dev) if (dev->close) dev->input_dev->close = ir_close; - do { - devno = find_first_zero_bit(ir_core_dev_number, - IRRCV_NUM_DEVICES); - /* No free device slots */ - if (devno >= IRRCV_NUM_DEVICES) - return -ENOMEM; - } while (test_and_set_bit(devno, ir_core_dev_number)); + minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL); + if (minor < 0) + return minor; + + dev->minor = minor; + dev_set_name(&dev->dev, "rc%u", dev->minor); + dev_set_drvdata(&dev->dev, dev); dev->dev.groups = dev->sysfs_groups; dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp; @@ -1360,9 +1366,6 @@ int rc_register_device(struct rc_dev *dev) */ mutex_lock(&dev->lock); - dev->devno = devno; - dev_set_name(&dev->dev, "rc%ld", dev->devno); - dev_set_drvdata(&dev->dev, dev); rc = device_add(&dev->dev); if (rc) goto out_unlock; @@ -1428,8 +1431,6 @@ int rc_register_device(struct rc_dev *dev) if (dev->change_protocol) { u64 rc_type = (1ll << rc_map->rc_type); - if (dev->driver_type == RC_DRIVER_IR_RAW) - rc_type |= RC_BIT_LIRC; rc = dev->change_protocol(dev, &rc_type); if (rc < 0) goto out_raw; @@ -1438,8 +1439,8 @@ int rc_register_device(struct rc_dev *dev) mutex_unlock(&dev->lock); - IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n", - dev->devno, + IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n", + dev->minor, dev->driver_name ? dev->driver_name : "unknown", rc_map->name ? rc_map->name : "unknown", dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked"); @@ -1458,7 +1459,7 @@ out_dev: device_del(&dev->dev); out_unlock: mutex_unlock(&dev->lock); - clear_bit(dev->devno, ir_core_dev_number); + ida_simple_remove(&rc_ida, minor); return rc; } EXPORT_SYMBOL_GPL(rc_register_device); @@ -1470,8 +1471,6 @@ void rc_unregister_device(struct rc_dev *dev) del_timer_sync(&dev->timer_keyup); - clear_bit(dev->devno, ir_core_dev_number); - if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); @@ -1484,6 +1483,8 @@ void rc_unregister_device(struct rc_dev *dev) device_del(&dev->dev); + ida_simple_remove(&rc_ida, dev->minor); + rc_free_device(dev); } diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 4cc55b3a0558..3721ee63b8fb 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -348,15 +348,16 @@ static void lme2510_int_response(struct urb *lme_urb) switch (ibuf[0]) { case 0xaa: debug_data_snipet(1, "INT Remote data snipet", ibuf); - if ((ibuf[4] + ibuf[5]) == 0xff) { - key = RC_SCANCODE_NECX((ibuf[2] ^ 0xff) << 8 | - (ibuf[3] > 0) ? (ibuf[3] ^ 0xff) : 0, - ibuf[5]); - deb_info(1, "INT Key =%08x", key); - if (adap_to_d(adap)->rc_dev != NULL) - rc_keydown(adap_to_d(adap)->rc_dev, - RC_TYPE_NEC, key, 0); - } + if (!adap_to_d(adap)->rc_dev) + break; + + key = RC_SCANCODE_NEC32(ibuf[2] << 24 | + ibuf[3] << 16 | + ibuf[4] << 8 | + ibuf[5]); + + deb_info(1, "INT Key = 0x%08x", key); + rc_keydown(adap_to_d(adap)->rc_dev, RC_TYPE_NEC, key, 0); break; case 0xbb: switch (st->tuner_config) { @@ -1344,7 +1345,7 @@ module_usb_driver(lme2510_driver); MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); -MODULE_VERSION("2.06"); +MODULE_VERSION("2.07"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(LME2510_C_S7395); MODULE_FIRMWARE(LME2510_C_LG); diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c index 7cbc3a00bda8..bf6b215438e3 100644 --- a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c +++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c @@ -177,7 +177,7 @@ static int rotation_thread_function(void *data) __s32 vflip, hflip; set_current_state(TASK_INTERRUPTIBLE); - while (!schedule_timeout(100)) { + while (!schedule_timeout(msecs_to_jiffies(100))) { if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock)) break; diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c index c75b7388a85c..4f2050a5ec94 100644 --- a/drivers/media/usb/gspca/sn9c2028.c +++ b/drivers/media/usb/gspca/sn9c2028.c @@ -140,7 +140,7 @@ static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command) status = sn9c2028_read1(gspca_dev); if (status < 0) { pr_err("long command status read error %d\n", status); - return (status < 0) ? status : -EIO; + return status; } memset(reading, 0, 4); diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 4d313ed4c32e..7291cca58704 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -194,6 +194,8 @@ static int stk1160_start_streaming(struct stk1160 *dev) /* Start saa711x */ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); + dev->sequence = 0; + /* Start stk1160 */ stk1160_write_reg(dev, STK1160_DCTRL, 0xb3); stk1160_write_reg(dev, STK1160_DCTRL+3, 0x00); diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 39f1aae209bc..940c3eaea507 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -96,9 +96,7 @@ void stk1160_buffer_done(struct stk1160 *dev) { struct stk1160_buffer *buf = dev->isoc_ctl.buf; - dev->field_count++; - - buf->vb.v4l2_buf.sequence = dev->field_count >> 1; + buf->vb.v4l2_buf.sequence = dev->sequence++; buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; buf->vb.v4l2_buf.bytesused = buf->bytesused; v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index abdea484c998..3922a6cabde2 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -151,8 +151,7 @@ struct stk1160 { v4l2_std_id norm; /* current norm */ struct stk1160_fmt *fmt; /* selected format */ - unsigned int field_count; /* not sure ??? */ - enum v4l2_field field; /* also not sure :/ */ + unsigned int sequence; /* i2c i/o */ struct i2c_adapter i2c_adap; diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 322b53a4f1dd..7c3a7c55d969 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -593,14 +593,9 @@ static void ttusb_dec_process_packet(struct ttusb_dec *dec) static void swap_bytes(u8 *b, int length) { - u8 c; - length -= length % 2; - for (; length; b += 2, length -= 2) { - c = *b; - *b = *(b + 1); - *(b + 1) = c; - } + for (; length; b += 2, length -= 2) + swap(*b, *(b + 1)); } static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index e3a3468002e6..b6b7dcc1b77d 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1678,21 +1678,6 @@ static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new) unsigned idx; int err = 0; - if (!ctrl->is_ptr) { - switch (ctrl->type) { - case V4L2_CTRL_TYPE_INTEGER: - case V4L2_CTRL_TYPE_INTEGER_MENU: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_BITMASK: - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_BUTTON: - case V4L2_CTRL_TYPE_CTRL_CLASS: - case V4L2_CTRL_TYPE_INTEGER64: - return ctrl->type_ops->validate(ctrl, 0, p_new); - default: - break; - } - } for (idx = 0; !err && idx < ctrl->elems; idx++) err = ctrl->type_ops->validate(ctrl, idx, p_new); return err; diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 04dc71e3ebf0..6a83d6191684 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -256,6 +256,7 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, { const struct v4l2_bt_timings *bt = &t->bt; u32 htot, vtot; + u32 fps; if (t->type != V4L2_DV_BT_656_1120) return; @@ -265,13 +266,15 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, if (bt->interlaced) vtot /= 2; + fps = (htot * vtot) > 0 ? div_u64((100 * (u64)bt->pixelclock), + (htot * vtot)) : 0; + if (prefix == NULL) prefix = ""; - pr_info("%s: %s%ux%u%s%u (%ux%u)\n", dev_prefix, prefix, + pr_info("%s: %s%ux%u%s%u.%u (%ux%u)\n", dev_prefix, prefix, bt->width, bt->height, bt->interlaced ? "i" : "p", - (htot * vtot) > 0 ? ((u32)bt->pixelclock / (htot * vtot)) : 0, - htot, vtot); + fps / 100, fps % 100, htot, vtot); if (!detailed) return; @@ -290,9 +293,11 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-", bt->il_vsync, bt->il_vbackporch); pr_info("%s: pixelclock: %llu\n", dev_prefix, bt->pixelclock); - pr_info("%s: flags (0x%x):%s%s%s%s%s\n", dev_prefix, bt->flags, + pr_info("%s: flags (0x%x):%s%s%s%s%s%s\n", dev_prefix, bt->flags, (bt->flags & V4L2_DV_FL_REDUCED_BLANKING) ? " REDUCED_BLANKING" : "", + ((bt->flags & V4L2_DV_FL_REDUCED_BLANKING) && + bt->vsync == 8) ? " (V2)" : "", (bt->flags & V4L2_DV_FL_CAN_REDUCE_FPS) ? " CAN_REDUCE_FPS" : "", (bt->flags & V4L2_DV_FL_REDUCED_FPS) ? @@ -316,6 +321,7 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); */ #define CVT_PXL_CLK_GRAN 250000 /* pixel clock granularity */ +#define CVT_PXL_CLK_GRAN_RB_V2 1000 /* granularity for reduced blanking v2*/ /* Normal blanking */ #define CVT_MIN_V_BPORCH 7 /* lines */ @@ -335,15 +341,22 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); /* Reduced Blanking */ #define CVT_RB_MIN_V_BPORCH 7 /* lines */ #define CVT_RB_V_FPORCH 3 /* lines */ -#define CVT_RB_MIN_V_BLANK 460 /* us */ +#define CVT_RB_MIN_V_BLANK 460 /* us */ #define CVT_RB_H_SYNC 32 /* pixels */ -#define CVT_RB_H_BPORCH 80 /* pixels */ #define CVT_RB_H_BLANK 160 /* pixels */ +/* Reduce blanking Version 2 */ +#define CVT_RB_V2_H_BLANK 80 /* pixels */ +#define CVT_RB_MIN_V_FPORCH 3 /* lines */ +#define CVT_RB_V2_MIN_V_FPORCH 1 /* lines */ +#define CVT_RB_V_BPORCH 6 /* lines */ /** v4l2_detect_cvt - detect if the given timings follow the CVT standard * @frame_height - the total height of the frame (including blanking) in lines. * @hfreq - the horizontal frequency in Hz. * @vsync - the height of the vertical sync in lines. + * @active_width - active width of image (does not include blanking). This + * information is needed only in case of version 2 of reduced blanking. + * In other cases, this parameter does not have any effect on timings. * @polarities - the horizontal and vertical polarities (same as struct * v4l2_bt_timings polarities). * @interlaced - if this flag is true, it indicates interlaced format @@ -352,20 +365,22 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); * This function will attempt to detect if the given values correspond to a * valid CVT format. If so, then it will return true, and fmt will be filled * in with the found CVT timings. - * - * TODO: VESA defined a new version 2 of their reduced blanking - * formula. Support for that is currently missing in this CVT - * detection function. */ -bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, - u32 polarities, bool interlaced, struct v4l2_dv_timings *fmt) +bool v4l2_detect_cvt(unsigned frame_height, + unsigned hfreq, + unsigned vsync, + unsigned active_width, + u32 polarities, + bool interlaced, + struct v4l2_dv_timings *fmt) { int v_fp, v_bp, h_fp, h_bp, hsync; int frame_width, image_height, image_width; bool reduced_blanking; + bool rb_v2 = false; unsigned pix_clk; - if (vsync < 4 || vsync > 7) + if (vsync < 4 || vsync > 8) return false; if (polarities == V4L2_DV_VSYNC_POS_POL) @@ -375,17 +390,35 @@ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, else return false; + if (reduced_blanking && vsync == 8) + rb_v2 = true; + + if (rb_v2 && active_width == 0) + return false; + + if (!rb_v2 && vsync > 7) + return false; + if (hfreq == 0) return false; /* Vertical */ if (reduced_blanking) { - v_fp = CVT_RB_V_FPORCH; - v_bp = (CVT_RB_MIN_V_BLANK * hfreq) / 1000000 + 1; - v_bp -= vsync + v_fp; - - if (v_bp < CVT_RB_MIN_V_BPORCH) - v_bp = CVT_RB_MIN_V_BPORCH; + if (rb_v2) { + v_bp = CVT_RB_V_BPORCH; + v_fp = (CVT_RB_MIN_V_BLANK * hfreq) / 1000000 + 1; + v_fp -= vsync + v_bp; + + if (v_fp < CVT_RB_V2_MIN_V_FPORCH) + v_fp = CVT_RB_V2_MIN_V_FPORCH; + } else { + v_fp = CVT_RB_V_FPORCH; + v_bp = (CVT_RB_MIN_V_BLANK * hfreq) / 1000000 + 1; + v_bp -= vsync + v_fp; + + if (v_bp < CVT_RB_MIN_V_BPORCH) + v_bp = CVT_RB_MIN_V_BPORCH; + } } else { v_fp = CVT_MIN_V_PORCH_RND; v_bp = (CVT_MIN_VSYNC_BP * hfreq) / 1000000 + 1 - vsync; @@ -422,22 +455,32 @@ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, else return false; break; + case 8: + image_width = active_width; + break; default: return false; } - image_width = image_width & ~7; + if (!rb_v2) + image_width = image_width & ~7; /* Horizontal */ if (reduced_blanking) { - pix_clk = (image_width + CVT_RB_H_BLANK) * hfreq; - pix_clk = (pix_clk / CVT_PXL_CLK_GRAN) * CVT_PXL_CLK_GRAN; + int h_blank; + int clk_gran; - h_bp = CVT_RB_H_BPORCH; + h_blank = rb_v2 ? CVT_RB_V2_H_BLANK : CVT_RB_H_BLANK; + clk_gran = rb_v2 ? CVT_PXL_CLK_GRAN_RB_V2 : CVT_PXL_CLK_GRAN; + + pix_clk = (image_width + h_blank) * hfreq; + pix_clk = (pix_clk / clk_gran) * clk_gran; + + h_bp = h_blank / 2; hsync = CVT_RB_H_SYNC; - h_fp = CVT_RB_H_BLANK - h_bp - hsync; + h_fp = h_blank - h_bp - hsync; - frame_width = image_width + CVT_RB_H_BLANK; + frame_width = image_width + h_blank; } else { unsigned ideal_duty_cycle_per_myriad = 100 * CVT_C_PRIME - (CVT_M_PRIME * 100000) / hfreq; @@ -665,7 +708,6 @@ EXPORT_SYMBOL_GPL(v4l2_detect_gtf); struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait) { struct v4l2_fract aspect = { 16, 9 }; - u32 tmp; u8 ratio; /* Nothing filled in, fallback to 16:9 */ @@ -697,9 +739,7 @@ struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait) if (hor_landscape) return aspect; /* The aspect ratio is for portrait, so swap numerator and denominator */ - tmp = aspect.denominator; - aspect.denominator = aspect.numerator; - aspect.numerator = tmp; + swap(aspect.denominator, aspect.numerator); return aspect; } EXPORT_SYMBOL_GPL(v4l2_calc_aspect_ratio); diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index 8bc68e2b4052..fb55e5941445 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -342,14 +342,6 @@ static struct region_info region_configs[] = { .deemphasis = 50, .region = 3, }, - /* Japan wide band */ - { - .channel_spacing = 10, - .bottom_frequency = 76000, - .top_frequency = 108000, - .deemphasis = 50, - .region = 4, - }, }; /* @@ -741,6 +733,18 @@ static int bcm2048_set_region(struct bcm2048_device *bdev, u8 region) mutex_lock(&bdev->mutex); bdev->region_info = region_configs[region]; + + if (region_configs[region].bottom_frequency < 87500) + bdev->cache_fm_ctrl |= BCM2048_BAND_SELECT; + else + bdev->cache_fm_ctrl &= ~BCM2048_BAND_SELECT; + + err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL, + bdev->cache_fm_ctrl); + if (err) { + mutex_unlock(&bdev->mutex); + goto done; + } mutex_unlock(&bdev->mutex); if (bdev->frequency < region_configs[region].bottom_frequency || diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig index 072dac04a750..8d4e3bd1bfe1 100644 --- a/drivers/staging/media/omap4iss/Kconfig +++ b/drivers/staging/media/omap4iss/Kconfig @@ -1,5 +1,5 @@ config VIDEO_OMAP4 - bool "OMAP 4 Camera support" + tristate "OMAP 4 Camera support" depends on VIDEO_V4L2=y && VIDEO_V4L2_SUBDEV_API && I2C=y && ARCH_OMAP4 depends on HAS_DMA select MFD_SYSCON diff --git a/drivers/staging/media/omap4iss/TODO b/drivers/staging/media/omap4iss/TODO index fcde88860a2c..4d220ef82653 100644 --- a/drivers/staging/media/omap4iss/TODO +++ b/drivers/staging/media/omap4iss/TODO @@ -1,4 +1,3 @@ -* Make the driver compile as a module * Fix FIFO/buffer overflows and underflows * Replace dummy resizer code with a real implementation * Fix checkpatch errors and warnings diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 85c54fedddda..40405d8710a6 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -640,76 +640,6 @@ iss_video_try_format(struct file *file, void *fh, struct v4l2_format *format) } static int -iss_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_subdev *subdev; - int ret; - - subdev = iss_video_remote_subdev(video, NULL); - if (subdev == NULL) - return -EINVAL; - - mutex_lock(&video->mutex); - ret = v4l2_subdev_call(subdev, video, cropcap, cropcap); - mutex_unlock(&video->mutex); - - return ret == -ENOIOCTLCMD ? -ENOTTY : ret; -} - -static int -iss_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_subdev_format format; - struct v4l2_subdev *subdev; - u32 pad; - int ret; - - subdev = iss_video_remote_subdev(video, &pad); - if (subdev == NULL) - return -EINVAL; - - /* Try the get crop operation first and fallback to get format if not - * implemented. - */ - ret = v4l2_subdev_call(subdev, video, g_crop, crop); - if (ret != -ENOIOCTLCMD) - return ret; - - format.pad = pad; - format.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format); - if (ret < 0) - return ret == -ENOIOCTLCMD ? -ENOTTY : ret; - - crop->c.left = 0; - crop->c.top = 0; - crop->c.width = format.format.width; - crop->c.height = format.format.height; - - return 0; -} - -static int -iss_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_subdev *subdev; - int ret; - - subdev = iss_video_remote_subdev(video, NULL); - if (subdev == NULL) - return -EINVAL; - - mutex_lock(&video->mutex); - ret = v4l2_subdev_call(subdev, video, s_crop, crop); - mutex_unlock(&video->mutex); - - return ret == -ENOIOCTLCMD ? -ENOTTY : ret; -} - -static int iss_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a) { struct iss_video_fh *vfh = to_iss_video_fh(fh); @@ -1018,9 +948,6 @@ static const struct v4l2_ioctl_ops iss_video_ioctl_ops = { .vidioc_g_fmt_vid_out = iss_video_get_format, .vidioc_s_fmt_vid_out = iss_video_set_format, .vidioc_try_fmt_vid_out = iss_video_try_format, - .vidioc_cropcap = iss_video_cropcap, - .vidioc_g_crop = iss_video_get_crop, - .vidioc_s_crop = iss_video_set_crop, .vidioc_g_parm = iss_video_get_param, .vidioc_s_parm = iss_video_set_param, .vidioc_reqbufs = iss_video_reqbufs, diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 45534da57759..5642fbea886e 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -69,7 +69,7 @@ enum rc_filter_type { * @rc_map: current scan/key table * @lock: used to ensure we've filled in all protocol details before * anyone can call show_protocols or store_protocols - * @devno: unique remote control device number + * @minor: unique minor remote control device number * @raw: additional data for raw pulse/space devices * @input_dev: the input child device used to communicate events to userspace * @driver_type: specifies if protocol decoding is done in hardware or software @@ -131,7 +131,7 @@ struct rc_dev { const char *map_name; struct rc_map rc_map; struct mutex lock; - unsigned long devno; + unsigned int minor; struct ir_raw_event_ctrl *raw; struct input_dev *input_dev; enum rc_driver_type driver_type; diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 27763d5bd261..7c4bbc4dfab4 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -14,30 +14,28 @@ enum rc_type { RC_TYPE_UNKNOWN = 0, /* Protocol not known */ RC_TYPE_OTHER = 1, /* Protocol known but proprietary */ - RC_TYPE_LIRC = 2, /* Pass raw IR to lirc userspace */ - RC_TYPE_RC5 = 3, /* Philips RC5 protocol */ - RC_TYPE_RC5X = 4, /* Philips RC5x protocol */ - RC_TYPE_RC5_SZ = 5, /* StreamZap variant of RC5 */ - RC_TYPE_JVC = 6, /* JVC protocol */ - RC_TYPE_SONY12 = 7, /* Sony 12 bit protocol */ - RC_TYPE_SONY15 = 8, /* Sony 15 bit protocol */ - RC_TYPE_SONY20 = 9, /* Sony 20 bit protocol */ - RC_TYPE_NEC = 10, /* NEC protocol */ - RC_TYPE_SANYO = 11, /* Sanyo protocol */ - RC_TYPE_MCE_KBD = 12, /* RC6-ish MCE keyboard/mouse */ - RC_TYPE_RC6_0 = 13, /* Philips RC6-0-16 protocol */ - RC_TYPE_RC6_6A_20 = 14, /* Philips RC6-6A-20 protocol */ - RC_TYPE_RC6_6A_24 = 15, /* Philips RC6-6A-24 protocol */ - RC_TYPE_RC6_6A_32 = 16, /* Philips RC6-6A-32 protocol */ - RC_TYPE_RC6_MCE = 17, /* MCE (Philips RC6-6A-32 subtype) protocol */ - RC_TYPE_SHARP = 18, /* Sharp protocol */ - RC_TYPE_XMP = 19, /* XMP protocol */ + RC_TYPE_RC5 = 2, /* Philips RC5 protocol */ + RC_TYPE_RC5X = 3, /* Philips RC5x protocol */ + RC_TYPE_RC5_SZ = 4, /* StreamZap variant of RC5 */ + RC_TYPE_JVC = 5, /* JVC protocol */ + RC_TYPE_SONY12 = 6, /* Sony 12 bit protocol */ + RC_TYPE_SONY15 = 7, /* Sony 15 bit protocol */ + RC_TYPE_SONY20 = 8, /* Sony 20 bit protocol */ + RC_TYPE_NEC = 9, /* NEC protocol */ + RC_TYPE_SANYO = 10, /* Sanyo protocol */ + RC_TYPE_MCE_KBD = 11, /* RC6-ish MCE keyboard/mouse */ + RC_TYPE_RC6_0 = 12, /* Philips RC6-0-16 protocol */ + RC_TYPE_RC6_6A_20 = 13, /* Philips RC6-6A-20 protocol */ + RC_TYPE_RC6_6A_24 = 14, /* Philips RC6-6A-24 protocol */ + RC_TYPE_RC6_6A_32 = 15, /* Philips RC6-6A-32 protocol */ + RC_TYPE_RC6_MCE = 16, /* MCE (Philips RC6-6A-32 subtype) protocol */ + RC_TYPE_SHARP = 17, /* Sharp protocol */ + RC_TYPE_XMP = 18, /* XMP protocol */ }; #define RC_BIT_NONE 0 #define RC_BIT_UNKNOWN (1 << RC_TYPE_UNKNOWN) #define RC_BIT_OTHER (1 << RC_TYPE_OTHER) -#define RC_BIT_LIRC (1 << RC_TYPE_LIRC) #define RC_BIT_RC5 (1 << RC_TYPE_RC5) #define RC_BIT_RC5X (1 << RC_TYPE_RC5X) #define RC_BIT_RC5_SZ (1 << RC_TYPE_RC5_SZ) @@ -56,7 +54,7 @@ enum rc_type { #define RC_BIT_SHARP (1 << RC_TYPE_SHARP) #define RC_BIT_XMP (1 << RC_TYPE_XMP) -#define RC_BIT_ALL (RC_BIT_UNKNOWN | RC_BIT_OTHER | RC_BIT_LIRC | \ +#define RC_BIT_ALL (RC_BIT_UNKNOWN | RC_BIT_OTHER | \ RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \ RC_BIT_JVC | \ RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \ diff --git a/include/media/v4l2-dv-timings.h b/include/media/v4l2-dv-timings.h index eecd3102a618..e18a653549cd 100644 --- a/include/media/v4l2-dv-timings.h +++ b/include/media/v4l2-dv-timings.h @@ -115,6 +115,9 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, * @frame_height - the total height of the frame (including blanking) in lines. * @hfreq - the horizontal frequency in Hz. * @vsync - the height of the vertical sync in lines. + * @active_width - active width of image (does not include blanking). This + * information is needed only in case of version 2 of reduced blanking. + * In other cases, this parameter does not have any effect on timings. * @polarities - the horizontal and vertical polarities (same as struct * v4l2_bt_timings polarities). * @interlaced - if this flag is true, it indicates interlaced format @@ -125,7 +128,8 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, * in with the found CVT timings. */ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, - u32 polarities, bool interlaced, struct v4l2_dv_timings *fmt); + unsigned active_width, u32 polarities, bool interlaced, + struct v4l2_dv_timings *fmt); /** v4l2_detect_gtf - detect if the given timings follow the GTF standard * @frame_height - the total height of the frame (including blanking) in lines. diff --git a/include/uapi/linux/vsp1.h b/include/uapi/linux/vsp1.h index e18858f6e865..9a823696d816 100644 --- a/include/uapi/linux/vsp1.h +++ b/include/uapi/linux/vsp1.h @@ -28,7 +28,7 @@ _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct vsp1_lut_config) struct vsp1_lut_config { - u32 lut[256]; + __u32 lut[256]; }; #endif /* __VSP1_USER_H__ */ |