2019-06-04 16:11:33 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2011-06-20 19:21:16 +08:00
|
|
|
/*
|
|
|
|
* Driver for MT9P031 CMOS Image Sensor from Aptina
|
|
|
|
*
|
|
|
|
* Copyright (C) 2011, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
|
|
* Copyright (C) 2011, Javier Martin <javier.martin@vista-silicon.com>
|
|
|
|
* Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
|
|
|
|
*
|
|
|
|
* Based on the MT9V032 driver and Bastian Hecht's code.
|
|
|
|
*/
|
|
|
|
|
2012-12-22 03:11:55 +08:00
|
|
|
#include <linux/clk.h>
|
2011-06-20 19:21:16 +08:00
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/device.h>
|
2014-09-21 05:38:56 +08:00
|
|
|
#include <linux/gpio/consumer.h>
|
2011-06-20 19:21:16 +08:00
|
|
|
#include <linux/i2c.h>
|
|
|
|
#include <linux/log2.h>
|
2013-05-26 21:08:54 +08:00
|
|
|
#include <linux/module.h>
|
2013-10-18 11:07:11 +08:00
|
|
|
#include <linux/of.h>
|
2014-02-11 05:01:48 +08:00
|
|
|
#include <linux/of_graph.h>
|
2011-06-20 19:21:16 +08:00
|
|
|
#include <linux/pm.h>
|
2012-05-08 21:10:36 +08:00
|
|
|
#include <linux/regulator/consumer.h>
|
2011-06-20 19:21:16 +08:00
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/videodev2.h>
|
|
|
|
|
2015-11-10 22:01:44 +08:00
|
|
|
#include <media/i2c/mt9p031.h>
|
2015-02-28 00:10:19 +08:00
|
|
|
#include <media/v4l2-async.h>
|
2011-06-20 19:21:16 +08:00
|
|
|
#include <media/v4l2-ctrls.h>
|
|
|
|
#include <media/v4l2-device.h>
|
2021-07-26 15:35:14 +08:00
|
|
|
#include <media/v4l2-fwnode.h>
|
2011-06-20 19:21:16 +08:00
|
|
|
#include <media/v4l2-subdev.h>
|
|
|
|
|
2012-02-26 00:25:57 +08:00
|
|
|
#include "aptina-pll.h"
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
#define MT9P031_PIXEL_ARRAY_WIDTH 2752
|
|
|
|
#define MT9P031_PIXEL_ARRAY_HEIGHT 2004
|
|
|
|
|
|
|
|
#define MT9P031_CHIP_VERSION 0x00
|
|
|
|
#define MT9P031_CHIP_VERSION_VALUE 0x1801
|
|
|
|
#define MT9P031_ROW_START 0x01
|
|
|
|
#define MT9P031_ROW_START_MIN 0
|
|
|
|
#define MT9P031_ROW_START_MAX 2004
|
|
|
|
#define MT9P031_ROW_START_DEF 54
|
|
|
|
#define MT9P031_COLUMN_START 0x02
|
|
|
|
#define MT9P031_COLUMN_START_MIN 0
|
|
|
|
#define MT9P031_COLUMN_START_MAX 2750
|
|
|
|
#define MT9P031_COLUMN_START_DEF 16
|
|
|
|
#define MT9P031_WINDOW_HEIGHT 0x03
|
|
|
|
#define MT9P031_WINDOW_HEIGHT_MIN 2
|
|
|
|
#define MT9P031_WINDOW_HEIGHT_MAX 2006
|
|
|
|
#define MT9P031_WINDOW_HEIGHT_DEF 1944
|
|
|
|
#define MT9P031_WINDOW_WIDTH 0x04
|
|
|
|
#define MT9P031_WINDOW_WIDTH_MIN 2
|
|
|
|
#define MT9P031_WINDOW_WIDTH_MAX 2752
|
|
|
|
#define MT9P031_WINDOW_WIDTH_DEF 2592
|
|
|
|
#define MT9P031_HORIZONTAL_BLANK 0x05
|
|
|
|
#define MT9P031_HORIZONTAL_BLANK_MIN 0
|
|
|
|
#define MT9P031_HORIZONTAL_BLANK_MAX 4095
|
|
|
|
#define MT9P031_VERTICAL_BLANK 0x06
|
2012-05-23 17:51:55 +08:00
|
|
|
#define MT9P031_VERTICAL_BLANK_MIN 1
|
|
|
|
#define MT9P031_VERTICAL_BLANK_MAX 4096
|
|
|
|
#define MT9P031_VERTICAL_BLANK_DEF 26
|
2011-06-20 19:21:16 +08:00
|
|
|
#define MT9P031_OUTPUT_CONTROL 0x07
|
|
|
|
#define MT9P031_OUTPUT_CONTROL_CEN 2
|
|
|
|
#define MT9P031_OUTPUT_CONTROL_SYN 1
|
|
|
|
#define MT9P031_OUTPUT_CONTROL_DEF 0x1f82
|
|
|
|
#define MT9P031_SHUTTER_WIDTH_UPPER 0x08
|
|
|
|
#define MT9P031_SHUTTER_WIDTH_LOWER 0x09
|
|
|
|
#define MT9P031_SHUTTER_WIDTH_MIN 1
|
|
|
|
#define MT9P031_SHUTTER_WIDTH_MAX 1048575
|
|
|
|
#define MT9P031_SHUTTER_WIDTH_DEF 1943
|
|
|
|
#define MT9P031_PLL_CONTROL 0x10
|
|
|
|
#define MT9P031_PLL_CONTROL_PWROFF 0x0050
|
|
|
|
#define MT9P031_PLL_CONTROL_PWRON 0x0051
|
|
|
|
#define MT9P031_PLL_CONTROL_USEPLL 0x0052
|
|
|
|
#define MT9P031_PLL_CONFIG_1 0x11
|
|
|
|
#define MT9P031_PLL_CONFIG_2 0x12
|
|
|
|
#define MT9P031_PIXEL_CLOCK_CONTROL 0x0a
|
2021-07-26 15:35:16 +08:00
|
|
|
#define MT9P031_PIXEL_CLOCK_INVERT BIT(15)
|
2014-02-10 04:31:47 +08:00
|
|
|
#define MT9P031_PIXEL_CLOCK_SHIFT(n) ((n) << 8)
|
|
|
|
#define MT9P031_PIXEL_CLOCK_DIVIDE(n) ((n) << 0)
|
2021-07-26 15:35:15 +08:00
|
|
|
#define MT9P031_RESTART 0x0b
|
2021-07-26 15:35:16 +08:00
|
|
|
#define MT9P031_FRAME_PAUSE_RESTART BIT(1)
|
|
|
|
#define MT9P031_FRAME_RESTART BIT(0)
|
2011-06-20 19:21:16 +08:00
|
|
|
#define MT9P031_SHUTTER_DELAY 0x0c
|
|
|
|
#define MT9P031_RST 0x0d
|
2021-07-26 15:35:16 +08:00
|
|
|
#define MT9P031_RST_ENABLE BIT(0)
|
2011-06-20 19:21:16 +08:00
|
|
|
#define MT9P031_READ_MODE_1 0x1e
|
|
|
|
#define MT9P031_READ_MODE_2 0x20
|
2021-07-26 15:35:16 +08:00
|
|
|
#define MT9P031_READ_MODE_2_ROW_MIR BIT(15)
|
|
|
|
#define MT9P031_READ_MODE_2_COL_MIR BIT(14)
|
|
|
|
#define MT9P031_READ_MODE_2_ROW_BLC BIT(6)
|
2011-06-20 19:21:16 +08:00
|
|
|
#define MT9P031_ROW_ADDRESS_MODE 0x22
|
|
|
|
#define MT9P031_COLUMN_ADDRESS_MODE 0x23
|
|
|
|
#define MT9P031_GLOBAL_GAIN 0x35
|
|
|
|
#define MT9P031_GLOBAL_GAIN_MIN 8
|
|
|
|
#define MT9P031_GLOBAL_GAIN_MAX 1024
|
|
|
|
#define MT9P031_GLOBAL_GAIN_DEF 8
|
2021-07-26 15:35:16 +08:00
|
|
|
#define MT9P031_GLOBAL_GAIN_MULT BIT(6)
|
2012-03-10 08:02:57 +08:00
|
|
|
#define MT9P031_ROW_BLACK_TARGET 0x49
|
2011-06-20 19:21:16 +08:00
|
|
|
#define MT9P031_ROW_BLACK_DEF_OFFSET 0x4b
|
2012-03-10 08:02:57 +08:00
|
|
|
#define MT9P031_GREEN1_OFFSET 0x60
|
|
|
|
#define MT9P031_GREEN2_OFFSET 0x61
|
|
|
|
#define MT9P031_BLACK_LEVEL_CALIBRATION 0x62
|
2021-07-26 15:35:16 +08:00
|
|
|
#define MT9P031_BLC_MANUAL_BLC BIT(0)
|
2012-03-10 08:02:57 +08:00
|
|
|
#define MT9P031_RED_OFFSET 0x63
|
|
|
|
#define MT9P031_BLUE_OFFSET 0x64
|
2011-06-20 19:21:16 +08:00
|
|
|
#define MT9P031_TEST_PATTERN 0xa0
|
|
|
|
#define MT9P031_TEST_PATTERN_SHIFT 3
|
2021-07-26 15:35:16 +08:00
|
|
|
#define MT9P031_TEST_PATTERN_ENABLE BIT(0)
|
2011-06-20 19:21:16 +08:00
|
|
|
#define MT9P031_TEST_PATTERN_GREEN 0xa1
|
|
|
|
#define MT9P031_TEST_PATTERN_RED 0xa2
|
|
|
|
#define MT9P031_TEST_PATTERN_BLUE 0xa3
|
|
|
|
|
2012-03-09 21:42:52 +08:00
|
|
|
enum mt9p031_model {
|
|
|
|
MT9P031_MODEL_COLOR,
|
|
|
|
MT9P031_MODEL_MONOCHROME,
|
|
|
|
};
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
struct mt9p031 {
|
|
|
|
struct v4l2_subdev subdev;
|
|
|
|
struct media_pad pad;
|
|
|
|
struct v4l2_rect crop; /* Sensor window */
|
|
|
|
struct v4l2_mbus_framefmt format;
|
|
|
|
struct mt9p031_platform_data *pdata;
|
|
|
|
struct mutex power_lock; /* lock to protect power_count */
|
|
|
|
int power_count;
|
|
|
|
|
2012-12-22 03:11:55 +08:00
|
|
|
struct clk *clk;
|
2013-06-08 15:50:42 +08:00
|
|
|
struct regulator_bulk_data regulators[3];
|
2012-05-08 21:10:36 +08:00
|
|
|
|
2012-03-09 21:42:52 +08:00
|
|
|
enum mt9p031_model model;
|
2012-02-26 00:25:57 +08:00
|
|
|
struct aptina_pll pll;
|
2014-02-10 04:31:47 +08:00
|
|
|
unsigned int clk_div;
|
|
|
|
bool use_pll;
|
2014-09-21 05:38:56 +08:00
|
|
|
struct gpio_desc *reset;
|
2011-06-20 19:21:16 +08:00
|
|
|
|
2012-03-10 08:02:57 +08:00
|
|
|
struct v4l2_ctrl_handler ctrls;
|
|
|
|
struct v4l2_ctrl *blc_auto;
|
|
|
|
struct v4l2_ctrl *blc_offset;
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
/* Registers cache */
|
|
|
|
u16 output_control;
|
|
|
|
u16 mode2;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct mt9p031 *to_mt9p031(struct v4l2_subdev *sd)
|
|
|
|
{
|
|
|
|
return container_of(sd, struct mt9p031, subdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_read(struct i2c_client *client, u8 reg)
|
|
|
|
{
|
2011-10-22 15:57:54 +08:00
|
|
|
return i2c_smbus_read_word_swapped(client, reg);
|
2011-06-20 19:21:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_write(struct i2c_client *client, u8 reg, u16 data)
|
|
|
|
{
|
2011-10-22 15:57:54 +08:00
|
|
|
return i2c_smbus_write_word_swapped(client, reg, data);
|
2011-06-20 19:21:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_set_output_control(struct mt9p031 *mt9p031, u16 clear,
|
|
|
|
u16 set)
|
|
|
|
{
|
|
|
|
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
|
|
|
u16 value = (mt9p031->output_control & ~clear) | set;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = mt9p031_write(client, MT9P031_OUTPUT_CONTROL, value);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
mt9p031->output_control = value;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_set_mode2(struct mt9p031 *mt9p031, u16 clear, u16 set)
|
|
|
|
{
|
|
|
|
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
|
|
|
u16 value = (mt9p031->mode2 & ~clear) | set;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = mt9p031_write(client, MT9P031_READ_MODE_2, value);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
mt9p031->mode2 = value;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_reset(struct mt9p031 *mt9p031)
|
|
|
|
{
|
|
|
|
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Disable chip output, synchronous option update */
|
|
|
|
ret = mt9p031_write(client, MT9P031_RST, MT9P031_RST_ENABLE);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2021-07-26 15:35:16 +08:00
|
|
|
ret = mt9p031_write(client, MT9P031_RST, 0);
|
2011-06-20 19:21:16 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-02-10 04:31:47 +08:00
|
|
|
ret = mt9p031_write(client, MT9P031_PIXEL_CLOCK_CONTROL,
|
|
|
|
MT9P031_PIXEL_CLOCK_DIVIDE(mt9p031->clk_div));
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
return mt9p031_set_output_control(mt9p031, MT9P031_OUTPUT_CONTROL_CEN,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
2012-12-22 03:11:55 +08:00
|
|
|
static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
|
2011-06-20 19:21:16 +08:00
|
|
|
{
|
2012-02-26 00:25:57 +08:00
|
|
|
static const struct aptina_pll_limits limits = {
|
|
|
|
.ext_clock_min = 6000000,
|
|
|
|
.ext_clock_max = 27000000,
|
|
|
|
.int_clock_min = 2000000,
|
|
|
|
.int_clock_max = 13500000,
|
|
|
|
.out_clock_min = 180000000,
|
|
|
|
.out_clock_max = 360000000,
|
|
|
|
.pix_clock_max = 96000000,
|
|
|
|
.n_min = 1,
|
|
|
|
.n_max = 64,
|
|
|
|
.m_min = 16,
|
|
|
|
.m_max = 255,
|
|
|
|
.p1_min = 1,
|
|
|
|
.p1_max = 128,
|
|
|
|
};
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
2012-02-26 00:25:57 +08:00
|
|
|
struct mt9p031_platform_data *pdata = mt9p031->pdata;
|
2021-07-26 15:35:13 +08:00
|
|
|
unsigned long ext_freq;
|
2014-01-21 13:20:57 +08:00
|
|
|
int ret;
|
2011-06-20 19:21:16 +08:00
|
|
|
|
2012-12-22 03:11:55 +08:00
|
|
|
mt9p031->clk = devm_clk_get(&client->dev, NULL);
|
|
|
|
if (IS_ERR(mt9p031->clk))
|
|
|
|
return PTR_ERR(mt9p031->clk);
|
|
|
|
|
2014-01-21 13:20:57 +08:00
|
|
|
ret = clk_set_rate(mt9p031->clk, pdata->ext_freq);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-12-22 03:11:55 +08:00
|
|
|
|
2021-07-26 15:35:13 +08:00
|
|
|
ext_freq = clk_get_rate(mt9p031->clk);
|
|
|
|
|
2014-02-10 04:31:47 +08:00
|
|
|
/* If the external clock frequency is out of bounds for the PLL use the
|
|
|
|
* pixel clock divider only and disable the PLL.
|
|
|
|
*/
|
2021-07-26 15:35:13 +08:00
|
|
|
if (ext_freq > limits.ext_clock_max) {
|
2014-02-10 04:31:47 +08:00
|
|
|
unsigned int div;
|
|
|
|
|
2021-07-26 15:35:13 +08:00
|
|
|
div = DIV_ROUND_UP(ext_freq, pdata->target_freq);
|
2014-02-10 04:31:47 +08:00
|
|
|
div = roundup_pow_of_two(div) / 2;
|
|
|
|
|
2015-02-04 22:53:32 +08:00
|
|
|
mt9p031->clk_div = min_t(unsigned int, div, 64);
|
2014-02-10 04:31:47 +08:00
|
|
|
mt9p031->use_pll = false;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2012-12-22 03:11:55 +08:00
|
|
|
|
2021-07-26 15:35:13 +08:00
|
|
|
mt9p031->pll.ext_clock = ext_freq;
|
2012-02-26 00:25:57 +08:00
|
|
|
mt9p031->pll.pix_clock = pdata->target_freq;
|
2014-02-10 04:31:47 +08:00
|
|
|
mt9p031->use_pll = true;
|
2011-06-20 19:21:16 +08:00
|
|
|
|
2012-02-26 00:25:57 +08:00
|
|
|
return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll);
|
2011-06-20 19:21:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
|
|
|
|
{
|
|
|
|
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
|
|
|
int ret;
|
|
|
|
|
2014-02-10 04:31:47 +08:00
|
|
|
if (!mt9p031->use_pll)
|
|
|
|
return 0;
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
ret = mt9p031_write(client, MT9P031_PLL_CONTROL,
|
|
|
|
MT9P031_PLL_CONTROL_PWRON);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = mt9p031_write(client, MT9P031_PLL_CONFIG_1,
|
2012-02-26 00:25:57 +08:00
|
|
|
(mt9p031->pll.m << 8) | (mt9p031->pll.n - 1));
|
2011-06-20 19:21:16 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2012-02-26 00:25:57 +08:00
|
|
|
ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll.p1 - 1);
|
2011-06-20 19:21:16 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
usleep_range(1000, 2000);
|
|
|
|
ret = mt9p031_write(client, MT9P031_PLL_CONTROL,
|
|
|
|
MT9P031_PLL_CONTROL_PWRON |
|
|
|
|
MT9P031_PLL_CONTROL_USEPLL);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
|
|
|
|
{
|
|
|
|
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
|
|
|
|
2014-02-10 04:31:47 +08:00
|
|
|
if (!mt9p031->use_pll)
|
|
|
|
return 0;
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
return mt9p031_write(client, MT9P031_PLL_CONTROL,
|
|
|
|
MT9P031_PLL_CONTROL_PWROFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_power_on(struct mt9p031 *mt9p031)
|
|
|
|
{
|
2022-08-24 06:22:16 +08:00
|
|
|
unsigned long rate, delay;
|
2013-06-08 15:50:42 +08:00
|
|
|
int ret;
|
|
|
|
|
2014-09-21 05:38:56 +08:00
|
|
|
/* Ensure RESET_BAR is active */
|
|
|
|
if (mt9p031->reset) {
|
|
|
|
gpiod_set_value(mt9p031->reset, 1);
|
2011-06-20 19:21:16 +08:00
|
|
|
usleep_range(1000, 2000);
|
|
|
|
}
|
|
|
|
|
2012-05-08 21:10:36 +08:00
|
|
|
/* Bring up the supplies */
|
2013-06-08 15:50:42 +08:00
|
|
|
ret = regulator_bulk_enable(ARRAY_SIZE(mt9p031->regulators),
|
|
|
|
mt9p031->regulators);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-05-08 21:10:36 +08:00
|
|
|
|
2014-02-09 00:31:58 +08:00
|
|
|
/* Enable clock */
|
2014-01-21 13:20:57 +08:00
|
|
|
if (mt9p031->clk) {
|
|
|
|
ret = clk_prepare_enable(mt9p031->clk);
|
|
|
|
if (ret) {
|
|
|
|
regulator_bulk_disable(ARRAY_SIZE(mt9p031->regulators),
|
|
|
|
mt9p031->regulators);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2011-06-20 19:21:16 +08:00
|
|
|
|
|
|
|
/* Now RESET_BAR must be high */
|
2014-09-21 05:38:56 +08:00
|
|
|
if (mt9p031->reset) {
|
|
|
|
gpiod_set_value(mt9p031->reset, 0);
|
2022-08-24 06:22:16 +08:00
|
|
|
/* Wait 850000 EXTCLK cycles before de-asserting reset. */
|
|
|
|
rate = clk_get_rate(mt9p031->clk);
|
|
|
|
if (!rate)
|
|
|
|
rate = 6000000; /* Slowest supported clock, 6 MHz */
|
|
|
|
delay = DIV_ROUND_UP(850000 * 1000, rate);
|
|
|
|
msleep(delay);
|
2011-06-20 19:21:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mt9p031_power_off(struct mt9p031 *mt9p031)
|
|
|
|
{
|
2014-09-21 05:38:56 +08:00
|
|
|
if (mt9p031->reset) {
|
|
|
|
gpiod_set_value(mt9p031->reset, 1);
|
2011-06-20 19:21:16 +08:00
|
|
|
usleep_range(1000, 2000);
|
|
|
|
}
|
|
|
|
|
2013-06-08 15:50:42 +08:00
|
|
|
regulator_bulk_disable(ARRAY_SIZE(mt9p031->regulators),
|
|
|
|
mt9p031->regulators);
|
2012-05-08 21:10:36 +08:00
|
|
|
|
2020-11-04 17:29:48 +08:00
|
|
|
clk_disable_unprepare(mt9p031->clk);
|
2011-06-20 19:21:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on)
|
|
|
|
{
|
|
|
|
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!on) {
|
|
|
|
mt9p031_power_off(mt9p031);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = mt9p031_power_on(mt9p031);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = mt9p031_reset(mt9p031);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(&client->dev, "Failed to reset the camera\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-07-26 15:35:14 +08:00
|
|
|
/* Configure the pixel clock polarity */
|
|
|
|
if (mt9p031->pdata && mt9p031->pdata->pixclk_pol) {
|
|
|
|
ret = mt9p031_write(client, MT9P031_PIXEL_CLOCK_CONTROL,
|
|
|
|
MT9P031_PIXEL_CLOCK_INVERT);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
return v4l2_ctrl_handler_setup(&mt9p031->ctrls);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
|
|
* V4L2 subdev video operations
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int mt9p031_set_params(struct mt9p031 *mt9p031)
|
|
|
|
{
|
|
|
|
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
|
|
|
struct v4l2_mbus_framefmt *format = &mt9p031->format;
|
|
|
|
const struct v4l2_rect *crop = &mt9p031->crop;
|
|
|
|
unsigned int hblank;
|
|
|
|
unsigned int vblank;
|
|
|
|
unsigned int xskip;
|
|
|
|
unsigned int yskip;
|
|
|
|
unsigned int xbin;
|
|
|
|
unsigned int ybin;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Windows position and size.
|
|
|
|
*
|
|
|
|
* TODO: Make sure the start coordinates and window size match the
|
|
|
|
* skipping, binning and mirroring (see description of registers 2 and 4
|
|
|
|
* in table 13, and Binning section on page 41).
|
|
|
|
*/
|
|
|
|
ret = mt9p031_write(client, MT9P031_COLUMN_START, crop->left);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = mt9p031_write(client, MT9P031_ROW_START, crop->top);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = mt9p031_write(client, MT9P031_WINDOW_WIDTH, crop->width - 1);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = mt9p031_write(client, MT9P031_WINDOW_HEIGHT, crop->height - 1);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* Row and column binning and skipping. Use the maximum binning value
|
|
|
|
* compatible with the skipping settings.
|
|
|
|
*/
|
|
|
|
xskip = DIV_ROUND_CLOSEST(crop->width, format->width);
|
|
|
|
yskip = DIV_ROUND_CLOSEST(crop->height, format->height);
|
|
|
|
xbin = 1 << (ffs(xskip) - 1);
|
|
|
|
ybin = 1 << (ffs(yskip) - 1);
|
|
|
|
|
|
|
|
ret = mt9p031_write(client, MT9P031_COLUMN_ADDRESS_MODE,
|
|
|
|
((xbin - 1) << 4) | (xskip - 1));
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = mt9p031_write(client, MT9P031_ROW_ADDRESS_MODE,
|
|
|
|
((ybin - 1) << 4) | (yskip - 1));
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* Blanking - use minimum value for horizontal blanking and default
|
|
|
|
* value for vertical blanking.
|
|
|
|
*/
|
2012-05-23 17:51:55 +08:00
|
|
|
hblank = 346 * ybin + 64 + (80 >> min_t(unsigned int, xbin, 3));
|
2011-06-20 19:21:16 +08:00
|
|
|
vblank = MT9P031_VERTICAL_BLANK_DEF;
|
|
|
|
|
2012-05-23 17:51:55 +08:00
|
|
|
ret = mt9p031_write(client, MT9P031_HORIZONTAL_BLANK, hblank - 1);
|
2011-06-20 19:21:16 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-05-23 17:51:55 +08:00
|
|
|
ret = mt9p031_write(client, MT9P031_VERTICAL_BLANK, vblank - 1);
|
2011-06-20 19:21:16 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable)
|
|
|
|
{
|
|
|
|
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
|
2021-07-26 15:35:15 +08:00
|
|
|
struct i2c_client *client = v4l2_get_subdevdata(subdev);
|
|
|
|
int val;
|
2011-06-20 19:21:16 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!enable) {
|
2021-07-26 15:35:15 +08:00
|
|
|
/* enable pause restart */
|
|
|
|
val = MT9P031_FRAME_PAUSE_RESTART;
|
|
|
|
ret = mt9p031_write(client, MT9P031_RESTART, val);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* enable restart + keep pause restart set */
|
|
|
|
val |= MT9P031_FRAME_RESTART;
|
|
|
|
ret = mt9p031_write(client, MT9P031_RESTART, val);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
/* Stop sensor readout */
|
|
|
|
ret = mt9p031_set_output_control(mt9p031,
|
|
|
|
MT9P031_OUTPUT_CONTROL_CEN, 0);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return mt9p031_pll_disable(mt9p031);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = mt9p031_set_params(mt9p031);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* Switch to master "normal" mode */
|
|
|
|
ret = mt9p031_set_output_control(mt9p031, 0,
|
|
|
|
MT9P031_OUTPUT_CONTROL_CEN);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2021-07-26 15:35:15 +08:00
|
|
|
/*
|
|
|
|
* - clear pause restart
|
|
|
|
* - don't clear restart as clearing restart manually can cause
|
|
|
|
* undefined behavior
|
|
|
|
*/
|
|
|
|
val = MT9P031_FRAME_RESTART;
|
|
|
|
ret = mt9p031_write(client, MT9P031_RESTART, val);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
return mt9p031_pll_enable(mt9p031);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev,
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
struct v4l2_subdev_state *sd_state,
|
2011-06-20 19:21:16 +08:00
|
|
|
struct v4l2_subdev_mbus_code_enum *code)
|
|
|
|
{
|
|
|
|
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
|
|
|
|
|
|
|
|
if (code->pad || code->index)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
code->code = mt9p031->format.code;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev,
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
struct v4l2_subdev_state *sd_state,
|
2011-06-20 19:21:16 +08:00
|
|
|
struct v4l2_subdev_frame_size_enum *fse)
|
|
|
|
{
|
|
|
|
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
|
|
|
|
|
|
|
|
if (fse->index >= 8 || fse->code != mt9p031->format.code)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
fse->min_width = MT9P031_WINDOW_WIDTH_DEF
|
|
|
|
/ min_t(unsigned int, 7, fse->index + 1);
|
|
|
|
fse->max_width = fse->min_width;
|
|
|
|
fse->min_height = MT9P031_WINDOW_HEIGHT_DEF / (fse->index + 1);
|
|
|
|
fse->max_height = fse->min_height;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct v4l2_mbus_framefmt *
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
__mt9p031_get_pad_format(struct mt9p031 *mt9p031,
|
|
|
|
struct v4l2_subdev_state *sd_state,
|
2011-06-20 19:21:16 +08:00
|
|
|
unsigned int pad, u32 which)
|
|
|
|
{
|
|
|
|
switch (which) {
|
|
|
|
case V4L2_SUBDEV_FORMAT_TRY:
|
media: v4l: subdev: Switch to stream-aware state functions
Switch all drivers accessing sub-device state to use the stream-aware
functions. We will soon remove the old ones.
This patch has been generated using the following Coccinelle script:
---------8<------------
@@
expression E1, E2, E3;
@@
- v4l2_subdev_get_pad_format(E1, E2, E3)
+ v4l2_subdev_state_get_format(E2, E3)
@@
expression E1, E2, E3;
@@
- v4l2_subdev_get_pad_crop(E1, E2, E3)
+ v4l2_subdev_state_get_crop(E2, E3)
@@
expression E1, E2, E3;
@@
- v4l2_subdev_get_pad_compose(E1, E2, E3)
+ v4l2_subdev_state_get_compose(E2, E3)
@@
expression E1, E2, E3;
@@
- v4l2_subdev_get_try_format(E1, E2, E3)
+ v4l2_subdev_state_get_format(E2, E3)
@@
expression E1, E2, E3;
@@
- v4l2_subdev_get_try_crop(E1, E2, E3)
+ v4l2_subdev_state_get_crop(E2, E3)
@@
expression E1, E2, E3;
@@
- v4l2_subdev_get_try_compose(E1, E2, E3)
+ v4l2_subdev_state_get_compose(E2, E3)
---------8<------------
Additionally drivers/media/i2c/s5k5baf.c and
drivers/media/platform/samsung/s3c-camif/camif-capture.c have been
manually changed as Coccinelle didn't. Further local variables have been
removed as they became unused as a result of the other changes.
Also Coccinelle introduced indentation by space in files
drivers/media/i2c/st-mipid02.c and
drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c. This has been also
corrected.
The diff from Coccinelle-generated changes are:
> diff --git b/drivers/media/i2c/imx319.c a/drivers/media/i2c/imx319.c
> index e549692ff478..420984382173 100644
> --- b/drivers/media/i2c/imx319.c
> +++ a/drivers/media/i2c/imx319.c
> @@ -2001,7 +2001,6 @@ static int imx319_do_get_pad_format(struct imx319 *imx319,
> struct v4l2_subdev_format *fmt)
> {
> struct v4l2_mbus_framefmt *framefmt;
> - struct v4l2_subdev *sd = &imx319->sd;
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> diff --git b/drivers/media/i2c/imx355.c a/drivers/media/i2c/imx355.c
> index 96bdde685d65..e1b1d2fc79dd 100644
> --- b/drivers/media/i2c/imx355.c
> +++ a/drivers/media/i2c/imx355.c
> @@ -1299,7 +1299,6 @@ static int imx355_do_get_pad_format(struct imx355 *imx355,
> struct v4l2_subdev_format *fmt)
> {
> struct v4l2_mbus_framefmt *framefmt;
> - struct v4l2_subdev *sd = &imx355->sd;
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> diff --git b/drivers/media/i2c/ov08x40.c a/drivers/media/i2c/ov08x40.c
> index ca799bbcfdb7..abbb0b774d43 100644
> --- b/drivers/media/i2c/ov08x40.c
> +++ a/drivers/media/i2c/ov08x40.c
> @@ -2774,7 +2774,6 @@ static int ov08x40_do_get_pad_format(struct ov08x40 *ov08x,
> struct v4l2_subdev_format *fmt)
> {
> struct v4l2_mbus_framefmt *framefmt;
> - struct v4l2_subdev *sd = &ov08x->sd;
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> diff --git b/drivers/media/i2c/ov13858.c a/drivers/media/i2c/ov13858.c
> index 7816d9787c61..09387e335d80 100644
> --- b/drivers/media/i2c/ov13858.c
> +++ a/drivers/media/i2c/ov13858.c
> @@ -1316,7 +1316,6 @@ static int ov13858_do_get_pad_format(struct ov13858 *ov13858,
> struct v4l2_subdev_format *fmt)
> {
> struct v4l2_mbus_framefmt *framefmt;
> - struct v4l2_subdev *sd = &ov13858->sd;
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> diff --git b/drivers/media/i2c/ov13b10.c a/drivers/media/i2c/ov13b10.c
> index 268cd4b03f9c..c06411d5ee2b 100644
> --- b/drivers/media/i2c/ov13b10.c
> +++ a/drivers/media/i2c/ov13b10.c
> @@ -1001,7 +1001,6 @@ static int ov13b10_do_get_pad_format(struct ov13b10 *ov13b,
> struct v4l2_subdev_format *fmt)
> {
> struct v4l2_mbus_framefmt *framefmt;
> - struct v4l2_subdev *sd = &ov13b->sd;
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> diff --git b/drivers/media/i2c/s5c73m3/s5c73m3-core.c a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
> index 47605e36bc60..8f9b5713daf7 100644
> --- b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
> +++ a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
> @@ -819,7 +819,6 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state,
> struct v4l2_subdev_format *fmt,
> const struct s5c73m3_frame_size **fs)
> {
> - struct v4l2_subdev *sd = &state->sensor_sd;
> u32 code;
>
> switch (fmt->pad) {
> diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
> index 67da2045f543..03ccfb0e1e11 100644
> --- a/drivers/media/i2c/s5k5baf.c
> +++ b/drivers/media/i2c/s5k5baf.c
> @@ -1472,14 +1472,11 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
>
> if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
> rects = (struct v4l2_rect * []) {
> - &s5k5baf_cis_rect,
> - v4l2_subdev_get_try_crop(sd, sd_state,
> - PAD_CIS),
> - v4l2_subdev_get_try_compose(sd, sd_state,
> - PAD_CIS),
> - v4l2_subdev_get_try_crop(sd, sd_state,
> - PAD_OUT)
> - };
> + &s5k5baf_cis_rect,
> + v4l2_subdev_state_get_crop(sd_state, PAD_CIS),
> + v4l2_subdev_state_get_compose(sd_state, PAD_CIS),
> + v4l2_subdev_state_get_crop(sd_state, PAD_OUT)
> + };
> s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
> return 0;
> }
> diff --git b/drivers/media/platform/samsung/s3c-camif/camif-capture.c a/drivers/media/platform/samsung/s3c-camif/camif-capture.c
> index 295e083f38e8..be58260ea67e 100644
> --- b/drivers/media/platform/samsung/s3c-camif/camif-capture.c
> +++ a/drivers/media/platform/samsung/s3c-camif/camif-capture.c
> @@ -1216,7 +1216,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
> struct v4l2_mbus_framefmt *mf = &fmt->format;
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
> + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> fmt->format = *mf;
> return 0;
> }
> @@ -1305,7 +1305,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
> __camif_subdev_try_format(camif, mf, fmt->pad);
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
> + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> *mf = fmt->format;
> mutex_unlock(&camif->lock);
> return 0;
> diff --git b/drivers/media/platform/ti/cal/cal-camerarx.c a/drivers/media/platform/ti/cal/cal-camerarx.c
> index cea454ed9c20..61433744c6c4 100644
> --- b/drivers/media/platform/ti/cal/cal-camerarx.c
> +++ a/drivers/media/platform/ti/cal/cal-camerarx.c
> @@ -621,8 +621,6 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
> struct v4l2_subdev_state *state,
> struct v4l2_subdev_mbus_code_enum *code)
> {
> - struct cal_camerarx *phy = to_cal_camerarx(sd);
> -
> /* No transcoding, source and sink codes must match. */
> if (cal_rx_pad_is_source(code->pad)) {
> struct v4l2_mbus_framefmt *fmt;
> diff --git b/drivers/staging/media/imx/imx-ic-prp.c a/drivers/staging/media/imx/imx-ic-prp.c
> index dd558fac6477..61d69f19657e 100644
> --- b/drivers/staging/media/imx/imx-ic-prp.c
> +++ a/drivers/staging/media/imx/imx-ic-prp.c
> @@ -82,8 +82,6 @@ static struct v4l2_mbus_framefmt *
> __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
> unsigned int pad, enum v4l2_subdev_format_whence which)
> {
> - struct imx_ic_priv *ic_priv = priv->ic_priv;
> -
> if (which == V4L2_SUBDEV_FORMAT_TRY)
> return v4l2_subdev_state_get_format(sd_state, pad);
> else
> diff --git b/drivers/staging/media/imx/imx-ic-prpencvf.c a/drivers/staging/media/imx/imx-ic-prpencvf.c
> index 02db7dbb884b..ec73c901079e 100644
> --- b/drivers/staging/media/imx/imx-ic-prpencvf.c
> +++ a/drivers/staging/media/imx/imx-ic-prpencvf.c
> @@ -790,8 +790,6 @@ static struct v4l2_mbus_framefmt *
> __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
> unsigned int pad, enum v4l2_subdev_format_whence which)
> {
> - struct imx_ic_priv *ic_priv = priv->ic_priv;
> -
> if (which == V4L2_SUBDEV_FORMAT_TRY)
> return v4l2_subdev_state_get_format(sd_state, pad);
> else
> diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c
> index 9c9361354c00..b08a249b5fdd 100644
> --- a/drivers/media/i2c/st-mipid02.c
> +++ b/drivers/media/i2c/st-mipid02.c
> @@ -751,7 +751,7 @@ static void mipid02_set_fmt_source(struct v4l2_subdev *sd,
> format->format = bridge->fmt;
> else
> format->format = *v4l2_subdev_state_get_format(sd_state,
> - MIPID02_SINK_0);
> + MIPID02_SINK_0);
>
> /* but code may need to be converted */
> format->format.code = serial_to_parallel_code(format->format.code);
> diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
> index 117912d3bfbd..96353648c032 100644
> --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
> +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
> @@ -319,7 +319,7 @@ static void rkisp1_isp_start(struct rkisp1_isp *isp,
> rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val);
>
> src_fmt = v4l2_subdev_state_get_format(sd_state,
> - RKISP1_ISP_PAD_SOURCE_VIDEO);
> + RKISP1_ISP_PAD_SOURCE_VIDEO);
> src_info = rkisp1_mbus_info_get_by_code(src_fmt->code);
>
> if (src_info->pixel_enc != V4L2_PIXEL_ENC_BAYER)
> @@ -475,9 +475,9 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
> sink_fmt = v4l2_subdev_state_get_format(sd_state,
> RKISP1_ISP_PAD_SINK_VIDEO);
> src_fmt = v4l2_subdev_state_get_format(sd_state,
> - RKISP1_ISP_PAD_SOURCE_VIDEO);
> + RKISP1_ISP_PAD_SOURCE_VIDEO);
> src_crop = v4l2_subdev_state_get_crop(sd_state,
> - RKISP1_ISP_PAD_SOURCE_VIDEO);
> + RKISP1_ISP_PAD_SOURCE_VIDEO);
>
> /*
> * Media bus code. The ISP can operate in pass-through mode (Bayer in,
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
2023-10-13 15:37:10 +08:00
|
|
|
return v4l2_subdev_state_get_format(sd_state, pad);
|
2011-06-20 19:21:16 +08:00
|
|
|
case V4L2_SUBDEV_FORMAT_ACTIVE:
|
|
|
|
return &mt9p031->format;
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct v4l2_rect *
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
__mt9p031_get_pad_crop(struct mt9p031 *mt9p031,
|
|
|
|
struct v4l2_subdev_state *sd_state,
|
|
|
|
unsigned int pad, u32 which)
|
2011-06-20 19:21:16 +08:00
|
|
|
{
|
|
|
|
switch (which) {
|
|
|
|
case V4L2_SUBDEV_FORMAT_TRY:
|
media: v4l: subdev: Switch to stream-aware state functions
Switch all drivers accessing sub-device state to use the stream-aware
functions. We will soon remove the old ones.
This patch has been generated using the following Coccinelle script:
---------8<------------
@@
expression E1, E2, E3;
@@
- v4l2_subdev_get_pad_format(E1, E2, E3)
+ v4l2_subdev_state_get_format(E2, E3)
@@
expression E1, E2, E3;
@@
- v4l2_subdev_get_pad_crop(E1, E2, E3)
+ v4l2_subdev_state_get_crop(E2, E3)
@@
expression E1, E2, E3;
@@
- v4l2_subdev_get_pad_compose(E1, E2, E3)
+ v4l2_subdev_state_get_compose(E2, E3)
@@
expression E1, E2, E3;
@@
- v4l2_subdev_get_try_format(E1, E2, E3)
+ v4l2_subdev_state_get_format(E2, E3)
@@
expression E1, E2, E3;
@@
- v4l2_subdev_get_try_crop(E1, E2, E3)
+ v4l2_subdev_state_get_crop(E2, E3)
@@
expression E1, E2, E3;
@@
- v4l2_subdev_get_try_compose(E1, E2, E3)
+ v4l2_subdev_state_get_compose(E2, E3)
---------8<------------
Additionally drivers/media/i2c/s5k5baf.c and
drivers/media/platform/samsung/s3c-camif/camif-capture.c have been
manually changed as Coccinelle didn't. Further local variables have been
removed as they became unused as a result of the other changes.
Also Coccinelle introduced indentation by space in files
drivers/media/i2c/st-mipid02.c and
drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c. This has been also
corrected.
The diff from Coccinelle-generated changes are:
> diff --git b/drivers/media/i2c/imx319.c a/drivers/media/i2c/imx319.c
> index e549692ff478..420984382173 100644
> --- b/drivers/media/i2c/imx319.c
> +++ a/drivers/media/i2c/imx319.c
> @@ -2001,7 +2001,6 @@ static int imx319_do_get_pad_format(struct imx319 *imx319,
> struct v4l2_subdev_format *fmt)
> {
> struct v4l2_mbus_framefmt *framefmt;
> - struct v4l2_subdev *sd = &imx319->sd;
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> diff --git b/drivers/media/i2c/imx355.c a/drivers/media/i2c/imx355.c
> index 96bdde685d65..e1b1d2fc79dd 100644
> --- b/drivers/media/i2c/imx355.c
> +++ a/drivers/media/i2c/imx355.c
> @@ -1299,7 +1299,6 @@ static int imx355_do_get_pad_format(struct imx355 *imx355,
> struct v4l2_subdev_format *fmt)
> {
> struct v4l2_mbus_framefmt *framefmt;
> - struct v4l2_subdev *sd = &imx355->sd;
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> diff --git b/drivers/media/i2c/ov08x40.c a/drivers/media/i2c/ov08x40.c
> index ca799bbcfdb7..abbb0b774d43 100644
> --- b/drivers/media/i2c/ov08x40.c
> +++ a/drivers/media/i2c/ov08x40.c
> @@ -2774,7 +2774,6 @@ static int ov08x40_do_get_pad_format(struct ov08x40 *ov08x,
> struct v4l2_subdev_format *fmt)
> {
> struct v4l2_mbus_framefmt *framefmt;
> - struct v4l2_subdev *sd = &ov08x->sd;
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> diff --git b/drivers/media/i2c/ov13858.c a/drivers/media/i2c/ov13858.c
> index 7816d9787c61..09387e335d80 100644
> --- b/drivers/media/i2c/ov13858.c
> +++ a/drivers/media/i2c/ov13858.c
> @@ -1316,7 +1316,6 @@ static int ov13858_do_get_pad_format(struct ov13858 *ov13858,
> struct v4l2_subdev_format *fmt)
> {
> struct v4l2_mbus_framefmt *framefmt;
> - struct v4l2_subdev *sd = &ov13858->sd;
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> diff --git b/drivers/media/i2c/ov13b10.c a/drivers/media/i2c/ov13b10.c
> index 268cd4b03f9c..c06411d5ee2b 100644
> --- b/drivers/media/i2c/ov13b10.c
> +++ a/drivers/media/i2c/ov13b10.c
> @@ -1001,7 +1001,6 @@ static int ov13b10_do_get_pad_format(struct ov13b10 *ov13b,
> struct v4l2_subdev_format *fmt)
> {
> struct v4l2_mbus_framefmt *framefmt;
> - struct v4l2_subdev *sd = &ov13b->sd;
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> diff --git b/drivers/media/i2c/s5c73m3/s5c73m3-core.c a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
> index 47605e36bc60..8f9b5713daf7 100644
> --- b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
> +++ a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
> @@ -819,7 +819,6 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state,
> struct v4l2_subdev_format *fmt,
> const struct s5c73m3_frame_size **fs)
> {
> - struct v4l2_subdev *sd = &state->sensor_sd;
> u32 code;
>
> switch (fmt->pad) {
> diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
> index 67da2045f543..03ccfb0e1e11 100644
> --- a/drivers/media/i2c/s5k5baf.c
> +++ b/drivers/media/i2c/s5k5baf.c
> @@ -1472,14 +1472,11 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
>
> if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
> rects = (struct v4l2_rect * []) {
> - &s5k5baf_cis_rect,
> - v4l2_subdev_get_try_crop(sd, sd_state,
> - PAD_CIS),
> - v4l2_subdev_get_try_compose(sd, sd_state,
> - PAD_CIS),
> - v4l2_subdev_get_try_crop(sd, sd_state,
> - PAD_OUT)
> - };
> + &s5k5baf_cis_rect,
> + v4l2_subdev_state_get_crop(sd_state, PAD_CIS),
> + v4l2_subdev_state_get_compose(sd_state, PAD_CIS),
> + v4l2_subdev_state_get_crop(sd_state, PAD_OUT)
> + };
> s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
> return 0;
> }
> diff --git b/drivers/media/platform/samsung/s3c-camif/camif-capture.c a/drivers/media/platform/samsung/s3c-camif/camif-capture.c
> index 295e083f38e8..be58260ea67e 100644
> --- b/drivers/media/platform/samsung/s3c-camif/camif-capture.c
> +++ a/drivers/media/platform/samsung/s3c-camif/camif-capture.c
> @@ -1216,7 +1216,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
> struct v4l2_mbus_framefmt *mf = &fmt->format;
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
> + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> fmt->format = *mf;
> return 0;
> }
> @@ -1305,7 +1305,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
> __camif_subdev_try_format(camif, mf, fmt->pad);
>
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> - mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
> + mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> *mf = fmt->format;
> mutex_unlock(&camif->lock);
> return 0;
> diff --git b/drivers/media/platform/ti/cal/cal-camerarx.c a/drivers/media/platform/ti/cal/cal-camerarx.c
> index cea454ed9c20..61433744c6c4 100644
> --- b/drivers/media/platform/ti/cal/cal-camerarx.c
> +++ a/drivers/media/platform/ti/cal/cal-camerarx.c
> @@ -621,8 +621,6 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
> struct v4l2_subdev_state *state,
> struct v4l2_subdev_mbus_code_enum *code)
> {
> - struct cal_camerarx *phy = to_cal_camerarx(sd);
> -
> /* No transcoding, source and sink codes must match. */
> if (cal_rx_pad_is_source(code->pad)) {
> struct v4l2_mbus_framefmt *fmt;
> diff --git b/drivers/staging/media/imx/imx-ic-prp.c a/drivers/staging/media/imx/imx-ic-prp.c
> index dd558fac6477..61d69f19657e 100644
> --- b/drivers/staging/media/imx/imx-ic-prp.c
> +++ a/drivers/staging/media/imx/imx-ic-prp.c
> @@ -82,8 +82,6 @@ static struct v4l2_mbus_framefmt *
> __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
> unsigned int pad, enum v4l2_subdev_format_whence which)
> {
> - struct imx_ic_priv *ic_priv = priv->ic_priv;
> -
> if (which == V4L2_SUBDEV_FORMAT_TRY)
> return v4l2_subdev_state_get_format(sd_state, pad);
> else
> diff --git b/drivers/staging/media/imx/imx-ic-prpencvf.c a/drivers/staging/media/imx/imx-ic-prpencvf.c
> index 02db7dbb884b..ec73c901079e 100644
> --- b/drivers/staging/media/imx/imx-ic-prpencvf.c
> +++ a/drivers/staging/media/imx/imx-ic-prpencvf.c
> @@ -790,8 +790,6 @@ static struct v4l2_mbus_framefmt *
> __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
> unsigned int pad, enum v4l2_subdev_format_whence which)
> {
> - struct imx_ic_priv *ic_priv = priv->ic_priv;
> -
> if (which == V4L2_SUBDEV_FORMAT_TRY)
> return v4l2_subdev_state_get_format(sd_state, pad);
> else
> diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c
> index 9c9361354c00..b08a249b5fdd 100644
> --- a/drivers/media/i2c/st-mipid02.c
> +++ b/drivers/media/i2c/st-mipid02.c
> @@ -751,7 +751,7 @@ static void mipid02_set_fmt_source(struct v4l2_subdev *sd,
> format->format = bridge->fmt;
> else
> format->format = *v4l2_subdev_state_get_format(sd_state,
> - MIPID02_SINK_0);
> + MIPID02_SINK_0);
>
> /* but code may need to be converted */
> format->format.code = serial_to_parallel_code(format->format.code);
> diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
> index 117912d3bfbd..96353648c032 100644
> --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
> +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
> @@ -319,7 +319,7 @@ static void rkisp1_isp_start(struct rkisp1_isp *isp,
> rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val);
>
> src_fmt = v4l2_subdev_state_get_format(sd_state,
> - RKISP1_ISP_PAD_SOURCE_VIDEO);
> + RKISP1_ISP_PAD_SOURCE_VIDEO);
> src_info = rkisp1_mbus_info_get_by_code(src_fmt->code);
>
> if (src_info->pixel_enc != V4L2_PIXEL_ENC_BAYER)
> @@ -475,9 +475,9 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
> sink_fmt = v4l2_subdev_state_get_format(sd_state,
> RKISP1_ISP_PAD_SINK_VIDEO);
> src_fmt = v4l2_subdev_state_get_format(sd_state,
> - RKISP1_ISP_PAD_SOURCE_VIDEO);
> + RKISP1_ISP_PAD_SOURCE_VIDEO);
> src_crop = v4l2_subdev_state_get_crop(sd_state,
> - RKISP1_ISP_PAD_SOURCE_VIDEO);
> + RKISP1_ISP_PAD_SOURCE_VIDEO);
>
> /*
> * Media bus code. The ISP can operate in pass-through mode (Bayer in,
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
2023-10-13 15:37:10 +08:00
|
|
|
return v4l2_subdev_state_get_crop(sd_state, pad);
|
2011-06-20 19:21:16 +08:00
|
|
|
case V4L2_SUBDEV_FORMAT_ACTIVE:
|
|
|
|
return &mt9p031->crop;
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_get_format(struct v4l2_subdev *subdev,
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
struct v4l2_subdev_state *sd_state,
|
2011-06-20 19:21:16 +08:00
|
|
|
struct v4l2_subdev_format *fmt)
|
|
|
|
{
|
|
|
|
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
|
|
|
|
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
fmt->format = *__mt9p031_get_pad_format(mt9p031, sd_state, fmt->pad,
|
2011-06-20 19:21:16 +08:00
|
|
|
fmt->which);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_set_format(struct v4l2_subdev *subdev,
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
struct v4l2_subdev_state *sd_state,
|
2011-06-20 19:21:16 +08:00
|
|
|
struct v4l2_subdev_format *format)
|
|
|
|
{
|
|
|
|
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
|
|
|
|
struct v4l2_mbus_framefmt *__format;
|
|
|
|
struct v4l2_rect *__crop;
|
|
|
|
unsigned int width;
|
|
|
|
unsigned int height;
|
|
|
|
unsigned int hratio;
|
|
|
|
unsigned int vratio;
|
|
|
|
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
__crop = __mt9p031_get_pad_crop(mt9p031, sd_state, format->pad,
|
2011-06-20 19:21:16 +08:00
|
|
|
format->which);
|
|
|
|
|
|
|
|
/* Clamp the width and height to avoid dividing by zero. */
|
|
|
|
width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
|
2013-11-26 16:31:42 +08:00
|
|
|
max_t(unsigned int, __crop->width / 7,
|
|
|
|
MT9P031_WINDOW_WIDTH_MIN),
|
2011-06-20 19:21:16 +08:00
|
|
|
__crop->width);
|
|
|
|
height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
|
2013-11-26 16:31:42 +08:00
|
|
|
max_t(unsigned int, __crop->height / 8,
|
|
|
|
MT9P031_WINDOW_HEIGHT_MIN),
|
|
|
|
__crop->height);
|
2011-06-20 19:21:16 +08:00
|
|
|
|
|
|
|
hratio = DIV_ROUND_CLOSEST(__crop->width, width);
|
|
|
|
vratio = DIV_ROUND_CLOSEST(__crop->height, height);
|
|
|
|
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
__format = __mt9p031_get_pad_format(mt9p031, sd_state, format->pad,
|
2011-06-20 19:21:16 +08:00
|
|
|
format->which);
|
|
|
|
__format->width = __crop->width / hratio;
|
|
|
|
__format->height = __crop->height / vratio;
|
|
|
|
|
|
|
|
format->format = *__format;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-04 17:54:52 +08:00
|
|
|
static int mt9p031_get_selection(struct v4l2_subdev *subdev,
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
struct v4l2_subdev_state *sd_state,
|
2014-12-04 17:54:52 +08:00
|
|
|
struct v4l2_subdev_selection *sel)
|
2011-06-20 19:21:16 +08:00
|
|
|
{
|
|
|
|
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
|
|
|
|
|
2022-06-19 08:31:58 +08:00
|
|
|
switch (sel->target) {
|
|
|
|
case V4L2_SEL_TGT_CROP_BOUNDS:
|
|
|
|
sel->r.left = MT9P031_COLUMN_START_MIN;
|
|
|
|
sel->r.top = MT9P031_ROW_START_MIN;
|
|
|
|
sel->r.width = MT9P031_WINDOW_WIDTH_MAX;
|
|
|
|
sel->r.height = MT9P031_WINDOW_HEIGHT_MAX;
|
|
|
|
return 0;
|
2014-12-04 17:54:52 +08:00
|
|
|
|
2022-06-19 08:31:58 +08:00
|
|
|
case V4L2_SEL_TGT_CROP:
|
|
|
|
sel->r = *__mt9p031_get_pad_crop(mt9p031, sd_state,
|
|
|
|
sel->pad, sel->which);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2011-06-20 19:21:16 +08:00
|
|
|
}
|
|
|
|
|
2014-12-04 17:54:52 +08:00
|
|
|
static int mt9p031_set_selection(struct v4l2_subdev *subdev,
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
struct v4l2_subdev_state *sd_state,
|
2014-12-04 17:54:52 +08:00
|
|
|
struct v4l2_subdev_selection *sel)
|
2011-06-20 19:21:16 +08:00
|
|
|
{
|
|
|
|
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
|
|
|
|
struct v4l2_mbus_framefmt *__format;
|
|
|
|
struct v4l2_rect *__crop;
|
|
|
|
struct v4l2_rect rect;
|
|
|
|
|
2014-12-04 17:54:52 +08:00
|
|
|
if (sel->target != V4L2_SEL_TGT_CROP)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
/* Clamp the crop rectangle boundaries and align them to a multiple of 2
|
|
|
|
* pixels to ensure a GRBG Bayer pattern.
|
|
|
|
*/
|
2014-12-04 17:54:52 +08:00
|
|
|
rect.left = clamp(ALIGN(sel->r.left, 2), MT9P031_COLUMN_START_MIN,
|
2011-06-20 19:21:16 +08:00
|
|
|
MT9P031_COLUMN_START_MAX);
|
2014-12-04 17:54:52 +08:00
|
|
|
rect.top = clamp(ALIGN(sel->r.top, 2), MT9P031_ROW_START_MIN,
|
2011-06-20 19:21:16 +08:00
|
|
|
MT9P031_ROW_START_MAX);
|
2014-12-04 17:54:52 +08:00
|
|
|
rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
|
2013-11-26 16:31:42 +08:00
|
|
|
MT9P031_WINDOW_WIDTH_MIN,
|
|
|
|
MT9P031_WINDOW_WIDTH_MAX);
|
2014-12-04 17:54:52 +08:00
|
|
|
rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
|
2013-11-26 16:31:42 +08:00
|
|
|
MT9P031_WINDOW_HEIGHT_MIN,
|
|
|
|
MT9P031_WINDOW_HEIGHT_MAX);
|
|
|
|
|
|
|
|
rect.width = min_t(unsigned int, rect.width,
|
|
|
|
MT9P031_PIXEL_ARRAY_WIDTH - rect.left);
|
|
|
|
rect.height = min_t(unsigned int, rect.height,
|
|
|
|
MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
|
2011-06-20 19:21:16 +08:00
|
|
|
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
__crop = __mt9p031_get_pad_crop(mt9p031, sd_state, sel->pad,
|
|
|
|
sel->which);
|
2011-06-20 19:21:16 +08:00
|
|
|
|
|
|
|
if (rect.width != __crop->width || rect.height != __crop->height) {
|
|
|
|
/* Reset the output image size if the crop rectangle size has
|
|
|
|
* been modified.
|
|
|
|
*/
|
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 22:55:58 +08:00
|
|
|
__format = __mt9p031_get_pad_format(mt9p031, sd_state,
|
|
|
|
sel->pad,
|
2014-12-04 17:54:52 +08:00
|
|
|
sel->which);
|
2011-06-20 19:21:16 +08:00
|
|
|
__format->width = rect.width;
|
|
|
|
__format->height = rect.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
*__crop = rect;
|
2014-12-04 17:54:52 +08:00
|
|
|
sel->r = rect;
|
2011-06-20 19:21:16 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-11-27 17:07:44 +08:00
|
|
|
static int mt9p031_init_state(struct v4l2_subdev *subdev,
|
|
|
|
struct v4l2_subdev_state *sd_state)
|
2022-06-19 07:54:43 +08:00
|
|
|
{
|
|
|
|
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
|
|
|
|
struct v4l2_mbus_framefmt *format;
|
|
|
|
struct v4l2_rect *crop;
|
|
|
|
const int which = sd_state == NULL ? V4L2_SUBDEV_FORMAT_ACTIVE :
|
|
|
|
V4L2_SUBDEV_FORMAT_TRY;
|
|
|
|
|
|
|
|
crop = __mt9p031_get_pad_crop(mt9p031, sd_state, 0, which);
|
|
|
|
crop->left = MT9P031_COLUMN_START_DEF;
|
|
|
|
crop->top = MT9P031_ROW_START_DEF;
|
|
|
|
crop->width = MT9P031_WINDOW_WIDTH_DEF;
|
|
|
|
crop->height = MT9P031_WINDOW_HEIGHT_DEF;
|
|
|
|
|
|
|
|
format = __mt9p031_get_pad_format(mt9p031, sd_state, 0, which);
|
|
|
|
|
|
|
|
if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
|
|
|
|
format->code = MEDIA_BUS_FMT_Y12_1X12;
|
|
|
|
else
|
|
|
|
format->code = MEDIA_BUS_FMT_SGRBG12_1X12;
|
|
|
|
|
|
|
|
format->width = MT9P031_WINDOW_WIDTH_DEF;
|
|
|
|
format->height = MT9P031_WINDOW_HEIGHT_DEF;
|
|
|
|
format->field = V4L2_FIELD_NONE;
|
|
|
|
format->colorspace = V4L2_COLORSPACE_SRGB;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
/* -----------------------------------------------------------------------------
|
|
|
|
* V4L2 subdev control operations
|
|
|
|
*/
|
|
|
|
|
2012-03-10 08:02:57 +08:00
|
|
|
#define V4L2_CID_BLC_AUTO (V4L2_CID_USER_BASE | 0x1002)
|
|
|
|
#define V4L2_CID_BLC_TARGET_LEVEL (V4L2_CID_USER_BASE | 0x1003)
|
|
|
|
#define V4L2_CID_BLC_ANALOG_OFFSET (V4L2_CID_USER_BASE | 0x1004)
|
|
|
|
#define V4L2_CID_BLC_DIGITAL_OFFSET (V4L2_CID_USER_BASE | 0x1005)
|
2011-06-20 19:21:16 +08:00
|
|
|
|
2014-05-08 21:03:37 +08:00
|
|
|
static int mt9p031_restore_blc(struct mt9p031 *mt9p031)
|
|
|
|
{
|
|
|
|
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (mt9p031->blc_auto->cur.val != 0) {
|
|
|
|
ret = mt9p031_set_mode2(mt9p031, 0,
|
|
|
|
MT9P031_READ_MODE_2_ROW_BLC);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mt9p031->blc_offset->cur.val != 0) {
|
|
|
|
ret = mt9p031_write(client, MT9P031_ROW_BLACK_TARGET,
|
|
|
|
mt9p031->blc_offset->cur.val);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
|
|
|
|
{
|
|
|
|
struct mt9p031 *mt9p031 =
|
|
|
|
container_of(ctrl->handler, struct mt9p031, ctrls);
|
|
|
|
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
|
|
|
|
u16 data;
|
|
|
|
int ret;
|
|
|
|
|
2014-05-07 23:34:34 +08:00
|
|
|
if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
|
|
|
|
return 0;
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
switch (ctrl->id) {
|
|
|
|
case V4L2_CID_EXPOSURE:
|
|
|
|
ret = mt9p031_write(client, MT9P031_SHUTTER_WIDTH_UPPER,
|
|
|
|
(ctrl->val >> 16) & 0xffff);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return mt9p031_write(client, MT9P031_SHUTTER_WIDTH_LOWER,
|
|
|
|
ctrl->val & 0xffff);
|
|
|
|
|
|
|
|
case V4L2_CID_GAIN:
|
|
|
|
/* Gain is controlled by 2 analog stages and a digital stage.
|
|
|
|
* Valid values for the 3 stages are
|
|
|
|
*
|
|
|
|
* Stage Min Max Step
|
|
|
|
* ------------------------------------------
|
|
|
|
* First analog stage x1 x2 1
|
|
|
|
* Second analog stage x1 x4 0.125
|
|
|
|
* Digital stage x1 x16 0.125
|
|
|
|
*
|
|
|
|
* To minimize noise, the gain stages should be used in the
|
|
|
|
* second analog stage, first analog stage, digital stage order.
|
|
|
|
* Gain from a previous stage should be pushed to its maximum
|
|
|
|
* value before the next stage is used.
|
|
|
|
*/
|
|
|
|
if (ctrl->val <= 32) {
|
|
|
|
data = ctrl->val;
|
|
|
|
} else if (ctrl->val <= 64) {
|
|
|
|
ctrl->val &= ~1;
|
|
|
|
data = (1 << 6) | (ctrl->val >> 1);
|
|
|
|
} else {
|
|
|
|
ctrl->val &= ~7;
|
|
|
|
data = ((ctrl->val - 64) << 5) | (1 << 6) | 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mt9p031_write(client, MT9P031_GLOBAL_GAIN, data);
|
|
|
|
|
|
|
|
case V4L2_CID_HFLIP:
|
|
|
|
if (ctrl->val)
|
|
|
|
return mt9p031_set_mode2(mt9p031,
|
|
|
|
0, MT9P031_READ_MODE_2_COL_MIR);
|
|
|
|
else
|
|
|
|
return mt9p031_set_mode2(mt9p031,
|
|
|
|
MT9P031_READ_MODE_2_COL_MIR, 0);
|
|
|
|
|
|
|
|
case V4L2_CID_VFLIP:
|
|
|
|
if (ctrl->val)
|
|
|
|
return mt9p031_set_mode2(mt9p031,
|
|
|
|
0, MT9P031_READ_MODE_2_ROW_MIR);
|
|
|
|
else
|
|
|
|
return mt9p031_set_mode2(mt9p031,
|
|
|
|
MT9P031_READ_MODE_2_ROW_MIR, 0);
|
|
|
|
|
|
|
|
case V4L2_CID_TEST_PATTERN:
|
2014-05-07 23:34:34 +08:00
|
|
|
/* The digital side of the Black Level Calibration function must
|
|
|
|
* be disabled when generating a test pattern to avoid artifacts
|
|
|
|
* in the image. Activate (deactivate) the BLC-related controls
|
|
|
|
* when the test pattern is enabled (disabled).
|
|
|
|
*/
|
|
|
|
v4l2_ctrl_activate(mt9p031->blc_auto, ctrl->val == 0);
|
|
|
|
v4l2_ctrl_activate(mt9p031->blc_offset, ctrl->val == 0);
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
if (!ctrl->val) {
|
2014-05-07 23:34:34 +08:00
|
|
|
/* Restore the BLC settings. */
|
2014-05-08 21:03:37 +08:00
|
|
|
ret = mt9p031_restore_blc(mt9p031);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2021-07-26 15:35:16 +08:00
|
|
|
return mt9p031_write(client, MT9P031_TEST_PATTERN, 0);
|
2011-06-20 19:21:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = mt9p031_write(client, MT9P031_TEST_PATTERN_GREEN, 0x05a0);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = mt9p031_write(client, MT9P031_TEST_PATTERN_RED, 0x0a50);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = mt9p031_write(client, MT9P031_TEST_PATTERN_BLUE, 0x0aa0);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-05-07 23:34:34 +08:00
|
|
|
/* Disable digital BLC when generating a test pattern. */
|
2011-06-20 19:21:16 +08:00
|
|
|
ret = mt9p031_set_mode2(mt9p031, MT9P031_READ_MODE_2_ROW_BLC,
|
|
|
|
0);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-03-10 08:02:57 +08:00
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
ret = mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET, 0);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return mt9p031_write(client, MT9P031_TEST_PATTERN,
|
|
|
|
((ctrl->val - 1) << MT9P031_TEST_PATTERN_SHIFT)
|
|
|
|
| MT9P031_TEST_PATTERN_ENABLE);
|
2012-03-10 08:02:57 +08:00
|
|
|
|
|
|
|
case V4L2_CID_BLC_AUTO:
|
|
|
|
ret = mt9p031_set_mode2(mt9p031,
|
|
|
|
ctrl->val ? 0 : MT9P031_READ_MODE_2_ROW_BLC,
|
|
|
|
ctrl->val ? MT9P031_READ_MODE_2_ROW_BLC : 0);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return mt9p031_write(client, MT9P031_BLACK_LEVEL_CALIBRATION,
|
|
|
|
ctrl->val ? 0 : MT9P031_BLC_MANUAL_BLC);
|
|
|
|
|
|
|
|
case V4L2_CID_BLC_TARGET_LEVEL:
|
|
|
|
return mt9p031_write(client, MT9P031_ROW_BLACK_TARGET,
|
|
|
|
ctrl->val);
|
|
|
|
|
|
|
|
case V4L2_CID_BLC_ANALOG_OFFSET:
|
|
|
|
data = ctrl->val & ((1 << 9) - 1);
|
|
|
|
|
|
|
|
ret = mt9p031_write(client, MT9P031_GREEN1_OFFSET, data);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = mt9p031_write(client, MT9P031_GREEN2_OFFSET, data);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = mt9p031_write(client, MT9P031_RED_OFFSET, data);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
return mt9p031_write(client, MT9P031_BLUE_OFFSET, data);
|
|
|
|
|
|
|
|
case V4L2_CID_BLC_DIGITAL_OFFSET:
|
|
|
|
return mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET,
|
|
|
|
ctrl->val & ((1 << 12) - 1));
|
2011-06-20 19:21:16 +08:00
|
|
|
}
|
2012-03-10 08:02:57 +08:00
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-14 06:05:17 +08:00
|
|
|
static const struct v4l2_ctrl_ops mt9p031_ctrl_ops = {
|
2011-06-20 19:21:16 +08:00
|
|
|
.s_ctrl = mt9p031_s_ctrl,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char * const mt9p031_test_pattern_menu[] = {
|
|
|
|
"Disabled",
|
|
|
|
"Color Field",
|
|
|
|
"Horizontal Gradient",
|
|
|
|
"Vertical Gradient",
|
|
|
|
"Diagonal Gradient",
|
|
|
|
"Classic Test Pattern",
|
|
|
|
"Walking 1s",
|
|
|
|
"Monochrome Horizontal Bars",
|
|
|
|
"Monochrome Vertical Bars",
|
|
|
|
"Vertical Color Bars",
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct v4l2_ctrl_config mt9p031_ctrls[] = {
|
|
|
|
{
|
2012-03-10 08:02:57 +08:00
|
|
|
.ops = &mt9p031_ctrl_ops,
|
|
|
|
.id = V4L2_CID_BLC_AUTO,
|
|
|
|
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
|
|
|
.name = "BLC, Auto",
|
|
|
|
.min = 0,
|
|
|
|
.max = 1,
|
|
|
|
.step = 1,
|
|
|
|
.def = 1,
|
|
|
|
.flags = 0,
|
|
|
|
}, {
|
|
|
|
.ops = &mt9p031_ctrl_ops,
|
|
|
|
.id = V4L2_CID_BLC_TARGET_LEVEL,
|
|
|
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
|
|
.name = "BLC Target Level",
|
|
|
|
.min = 0,
|
|
|
|
.max = 4095,
|
|
|
|
.step = 1,
|
|
|
|
.def = 168,
|
|
|
|
.flags = 0,
|
|
|
|
}, {
|
|
|
|
.ops = &mt9p031_ctrl_ops,
|
|
|
|
.id = V4L2_CID_BLC_ANALOG_OFFSET,
|
|
|
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
|
|
.name = "BLC Analog Offset",
|
|
|
|
.min = -255,
|
|
|
|
.max = 255,
|
|
|
|
.step = 1,
|
|
|
|
.def = 32,
|
|
|
|
.flags = 0,
|
|
|
|
}, {
|
|
|
|
.ops = &mt9p031_ctrl_ops,
|
|
|
|
.id = V4L2_CID_BLC_DIGITAL_OFFSET,
|
|
|
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
|
|
.name = "BLC Digital Offset",
|
|
|
|
.min = -2048,
|
|
|
|
.max = 2047,
|
|
|
|
.step = 1,
|
|
|
|
.def = 40,
|
|
|
|
.flags = 0,
|
2011-06-20 19:21:16 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
|
|
* V4L2 subdev core operations
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int mt9p031_set_power(struct v4l2_subdev *subdev, int on)
|
|
|
|
{
|
|
|
|
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
mutex_lock(&mt9p031->power_lock);
|
|
|
|
|
|
|
|
/* If the power count is modified from 0 to != 0 or from != 0 to 0,
|
|
|
|
* update the power state.
|
|
|
|
*/
|
|
|
|
if (mt9p031->power_count == !on) {
|
|
|
|
ret = __mt9p031_set_power(mt9p031, !!on);
|
|
|
|
if (ret < 0)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the power count. */
|
|
|
|
mt9p031->power_count += on ? 1 : -1;
|
|
|
|
WARN_ON(mt9p031->power_count < 0);
|
|
|
|
|
|
|
|
out:
|
|
|
|
mutex_unlock(&mt9p031->power_lock);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
|
|
* V4L2 subdev internal operations
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int mt9p031_registered(struct v4l2_subdev *subdev)
|
|
|
|
{
|
|
|
|
struct i2c_client *client = v4l2_get_subdevdata(subdev);
|
|
|
|
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
|
|
|
|
s32 data;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = mt9p031_power_on(mt9p031);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(&client->dev, "MT9P031 power up failed\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read out the chip version register */
|
|
|
|
data = mt9p031_read(client, MT9P031_CHIP_VERSION);
|
2013-04-19 05:35:39 +08:00
|
|
|
mt9p031_power_off(mt9p031);
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
if (data != MT9P031_CHIP_VERSION_VALUE) {
|
|
|
|
dev_err(&client->dev, "MT9P031 not detected, wrong version "
|
|
|
|
"0x%04x\n", data);
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev_info(&client->dev, "MT9P031 detected at address 0x%02x\n",
|
|
|
|
client->addr);
|
|
|
|
|
2013-04-19 05:35:39 +08:00
|
|
|
return 0;
|
2011-06-20 19:21:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
|
|
|
|
{
|
|
|
|
return mt9p031_set_power(subdev, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mt9p031_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
|
|
|
|
{
|
|
|
|
return mt9p031_set_power(subdev, 0);
|
|
|
|
}
|
|
|
|
|
2016-12-12 15:45:32 +08:00
|
|
|
static const struct v4l2_subdev_core_ops mt9p031_subdev_core_ops = {
|
2011-06-20 19:21:16 +08:00
|
|
|
.s_power = mt9p031_set_power,
|
|
|
|
};
|
|
|
|
|
2016-12-12 15:45:32 +08:00
|
|
|
static const struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = {
|
2011-06-20 19:21:16 +08:00
|
|
|
.s_stream = mt9p031_s_stream,
|
|
|
|
};
|
|
|
|
|
2016-12-12 15:45:32 +08:00
|
|
|
static const struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
|
2011-06-20 19:21:16 +08:00
|
|
|
.enum_mbus_code = mt9p031_enum_mbus_code,
|
|
|
|
.enum_frame_size = mt9p031_enum_frame_size,
|
|
|
|
.get_fmt = mt9p031_get_format,
|
|
|
|
.set_fmt = mt9p031_set_format,
|
2014-12-04 17:54:52 +08:00
|
|
|
.get_selection = mt9p031_get_selection,
|
|
|
|
.set_selection = mt9p031_set_selection,
|
2011-06-20 19:21:16 +08:00
|
|
|
};
|
|
|
|
|
2016-12-12 15:45:32 +08:00
|
|
|
static const struct v4l2_subdev_ops mt9p031_subdev_ops = {
|
2011-06-20 19:21:16 +08:00
|
|
|
.core = &mt9p031_subdev_core_ops,
|
|
|
|
.video = &mt9p031_subdev_video_ops,
|
|
|
|
.pad = &mt9p031_subdev_pad_ops,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = {
|
2023-11-27 17:07:44 +08:00
|
|
|
.init_state = mt9p031_init_state,
|
2011-06-20 19:21:16 +08:00
|
|
|
.registered = mt9p031_registered,
|
|
|
|
.open = mt9p031_open,
|
|
|
|
.close = mt9p031_close,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
|
|
* Driver initialization and probing
|
|
|
|
*/
|
|
|
|
|
2013-05-26 21:08:54 +08:00
|
|
|
static struct mt9p031_platform_data *
|
|
|
|
mt9p031_get_pdata(struct i2c_client *client)
|
|
|
|
{
|
2021-07-26 15:35:14 +08:00
|
|
|
struct mt9p031_platform_data *pdata = NULL;
|
2013-05-26 21:08:54 +08:00
|
|
|
struct device_node *np;
|
2021-07-26 15:35:14 +08:00
|
|
|
struct v4l2_fwnode_endpoint endpoint = {
|
|
|
|
.bus_type = V4L2_MBUS_PARALLEL
|
|
|
|
};
|
2013-05-26 21:08:54 +08:00
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
|
|
|
|
return client->dev.platform_data;
|
|
|
|
|
2024-02-20 09:16:21 +08:00
|
|
|
np = of_graph_get_endpoint_by_regs(client->dev.of_node, 0, -1);
|
2013-05-26 21:08:54 +08:00
|
|
|
if (!np)
|
|
|
|
return NULL;
|
|
|
|
|
2021-07-26 15:35:14 +08:00
|
|
|
if (v4l2_fwnode_endpoint_parse(of_fwnode_handle(np), &endpoint) < 0)
|
|
|
|
goto done;
|
|
|
|
|
2013-05-26 21:08:54 +08:00
|
|
|
pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
|
|
|
|
if (!pdata)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
of_property_read_u32(np, "input-clock-frequency", &pdata->ext_freq);
|
|
|
|
of_property_read_u32(np, "pixel-clock-frequency", &pdata->target_freq);
|
|
|
|
|
2021-07-26 15:35:14 +08:00
|
|
|
pdata->pixclk_pol = !!(endpoint.bus.parallel.flags &
|
|
|
|
V4L2_MBUS_PCLK_SAMPLE_RISING);
|
|
|
|
|
2013-05-26 21:08:54 +08:00
|
|
|
done:
|
|
|
|
of_node_put(np);
|
|
|
|
return pdata;
|
|
|
|
}
|
|
|
|
|
2022-11-19 06:41:25 +08:00
|
|
|
static int mt9p031_probe(struct i2c_client *client)
|
2011-06-20 19:21:16 +08:00
|
|
|
{
|
2022-11-19 06:41:25 +08:00
|
|
|
const struct i2c_device_id *did = i2c_client_get_device_id(client);
|
2013-05-26 21:08:54 +08:00
|
|
|
struct mt9p031_platform_data *pdata = mt9p031_get_pdata(client);
|
2019-06-08 18:55:48 +08:00
|
|
|
struct i2c_adapter *adapter = client->adapter;
|
2011-06-20 19:21:16 +08:00
|
|
|
struct mt9p031 *mt9p031;
|
|
|
|
unsigned int i;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (pdata == NULL) {
|
|
|
|
dev_err(&client->dev, "No platform data\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
|
|
|
|
dev_warn(&client->dev,
|
|
|
|
"I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2012-12-22 03:34:06 +08:00
|
|
|
mt9p031 = devm_kzalloc(&client->dev, sizeof(*mt9p031), GFP_KERNEL);
|
2011-06-20 19:21:16 +08:00
|
|
|
if (mt9p031 == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
mt9p031->pdata = pdata;
|
|
|
|
mt9p031->output_control = MT9P031_OUTPUT_CONTROL_DEF;
|
|
|
|
mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC;
|
2012-03-09 21:42:52 +08:00
|
|
|
mt9p031->model = did->driver_data;
|
2011-06-20 19:21:16 +08:00
|
|
|
|
2013-06-08 15:50:42 +08:00
|
|
|
mt9p031->regulators[0].supply = "vdd";
|
|
|
|
mt9p031->regulators[1].supply = "vdd_io";
|
|
|
|
mt9p031->regulators[2].supply = "vaa";
|
2012-05-08 21:10:36 +08:00
|
|
|
|
2013-06-08 15:50:42 +08:00
|
|
|
ret = devm_regulator_bulk_get(&client->dev, 3, mt9p031->regulators);
|
|
|
|
if (ret < 0) {
|
2012-05-08 21:10:36 +08:00
|
|
|
dev_err(&client->dev, "Unable to get regulators\n");
|
2013-06-08 15:50:42 +08:00
|
|
|
return ret;
|
2012-05-08 21:10:36 +08:00
|
|
|
}
|
|
|
|
|
2015-02-27 02:05:38 +08:00
|
|
|
mutex_init(&mt9p031->power_lock);
|
|
|
|
|
2012-09-25 20:35:43 +08:00
|
|
|
v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 6);
|
2011-06-20 19:21:16 +08:00
|
|
|
|
|
|
|
v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
|
|
|
|
V4L2_CID_EXPOSURE, MT9P031_SHUTTER_WIDTH_MIN,
|
|
|
|
MT9P031_SHUTTER_WIDTH_MAX, 1,
|
|
|
|
MT9P031_SHUTTER_WIDTH_DEF);
|
|
|
|
v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
|
|
|
|
V4L2_CID_GAIN, MT9P031_GLOBAL_GAIN_MIN,
|
|
|
|
MT9P031_GLOBAL_GAIN_MAX, 1, MT9P031_GLOBAL_GAIN_DEF);
|
|
|
|
v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
|
|
|
|
V4L2_CID_HFLIP, 0, 1, 1, 0);
|
|
|
|
v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
|
|
|
|
V4L2_CID_VFLIP, 0, 1, 1, 0);
|
2012-05-09 20:55:58 +08:00
|
|
|
v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
|
|
|
|
V4L2_CID_PIXEL_RATE, pdata->target_freq,
|
|
|
|
pdata->target_freq, 1, pdata->target_freq);
|
2012-09-25 20:35:43 +08:00
|
|
|
v4l2_ctrl_new_std_menu_items(&mt9p031->ctrls, &mt9p031_ctrl_ops,
|
|
|
|
V4L2_CID_TEST_PATTERN,
|
|
|
|
ARRAY_SIZE(mt9p031_test_pattern_menu) - 1, 0,
|
|
|
|
0, mt9p031_test_pattern_menu);
|
2011-06-20 19:21:16 +08:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(mt9p031_ctrls); ++i)
|
|
|
|
v4l2_ctrl_new_custom(&mt9p031->ctrls, &mt9p031_ctrls[i], NULL);
|
|
|
|
|
|
|
|
mt9p031->subdev.ctrl_handler = &mt9p031->ctrls;
|
|
|
|
|
2012-03-10 08:02:57 +08:00
|
|
|
if (mt9p031->ctrls.error) {
|
2011-06-20 19:21:16 +08:00
|
|
|
printk(KERN_INFO "%s: control initialization error %d\n",
|
|
|
|
__func__, mt9p031->ctrls.error);
|
2012-03-10 08:02:57 +08:00
|
|
|
ret = mt9p031->ctrls.error;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
mt9p031->blc_auto = v4l2_ctrl_find(&mt9p031->ctrls, V4L2_CID_BLC_AUTO);
|
|
|
|
mt9p031->blc_offset = v4l2_ctrl_find(&mt9p031->ctrls,
|
|
|
|
V4L2_CID_BLC_DIGITAL_OFFSET);
|
2011-06-20 19:21:16 +08:00
|
|
|
|
|
|
|
v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops);
|
|
|
|
mt9p031->subdev.internal_ops = &mt9p031_subdev_internal_ops;
|
|
|
|
|
2018-06-18 17:10:28 +08:00
|
|
|
mt9p031->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
|
2011-06-20 19:21:16 +08:00
|
|
|
mt9p031->pad.flags = MEDIA_PAD_FL_SOURCE;
|
2015-12-11 17:44:40 +08:00
|
|
|
ret = media_entity_pads_init(&mt9p031->subdev.entity, 1, &mt9p031->pad);
|
2011-06-20 19:21:16 +08:00
|
|
|
if (ret < 0)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
|
|
|
|
2023-11-27 17:07:44 +08:00
|
|
|
ret = mt9p031_init_state(&mt9p031->subdev, NULL);
|
2022-06-19 07:54:43 +08:00
|
|
|
if (ret)
|
|
|
|
goto done;
|
2011-06-20 19:21:16 +08:00
|
|
|
|
2014-09-21 05:38:56 +08:00
|
|
|
mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset",
|
|
|
|
GPIOD_OUT_HIGH);
|
2012-03-09 21:59:41 +08:00
|
|
|
|
2012-12-22 03:11:55 +08:00
|
|
|
ret = mt9p031_clk_setup(mt9p031);
|
2015-02-28 00:10:19 +08:00
|
|
|
if (ret)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
ret = v4l2_async_register_subdev(&mt9p031->subdev);
|
2011-06-20 19:21:16 +08:00
|
|
|
|
|
|
|
done:
|
|
|
|
if (ret < 0) {
|
|
|
|
v4l2_ctrl_handler_free(&mt9p031->ctrls);
|
|
|
|
media_entity_cleanup(&mt9p031->subdev.entity);
|
2015-02-27 02:05:38 +08:00
|
|
|
mutex_destroy(&mt9p031->power_lock);
|
2011-06-20 19:21:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-08-15 16:02:30 +08:00
|
|
|
static void mt9p031_remove(struct i2c_client *client)
|
2011-06-20 19:21:16 +08:00
|
|
|
{
|
|
|
|
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
|
|
|
|
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
|
|
|
|
|
|
|
|
v4l2_ctrl_handler_free(&mt9p031->ctrls);
|
2015-02-28 00:10:19 +08:00
|
|
|
v4l2_async_unregister_subdev(subdev);
|
2011-06-20 19:21:16 +08:00
|
|
|
media_entity_cleanup(&subdev->entity);
|
2015-02-27 02:05:38 +08:00
|
|
|
mutex_destroy(&mt9p031->power_lock);
|
2011-06-20 19:21:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct i2c_device_id mt9p031_id[] = {
|
2022-06-19 06:22:55 +08:00
|
|
|
{ "mt9p006", MT9P031_MODEL_COLOR },
|
2012-03-09 21:42:52 +08:00
|
|
|
{ "mt9p031", MT9P031_MODEL_COLOR },
|
|
|
|
{ "mt9p031m", MT9P031_MODEL_MONOCHROME },
|
2011-06-20 19:21:16 +08:00
|
|
|
{ }
|
|
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(i2c, mt9p031_id);
|
|
|
|
|
2013-05-26 21:08:54 +08:00
|
|
|
#if IS_ENABLED(CONFIG_OF)
|
|
|
|
static const struct of_device_id mt9p031_of_match[] = {
|
2022-06-19 06:22:55 +08:00
|
|
|
{ .compatible = "aptina,mt9p006", },
|
2013-05-26 21:08:54 +08:00
|
|
|
{ .compatible = "aptina,mt9p031", },
|
|
|
|
{ .compatible = "aptina,mt9p031m", },
|
|
|
|
{ /* sentinel */ },
|
|
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(of, mt9p031_of_match);
|
|
|
|
#endif
|
|
|
|
|
2011-06-20 19:21:16 +08:00
|
|
|
static struct i2c_driver mt9p031_i2c_driver = {
|
|
|
|
.driver = {
|
2013-05-26 21:08:54 +08:00
|
|
|
.of_match_table = of_match_ptr(mt9p031_of_match),
|
2011-06-20 19:21:16 +08:00
|
|
|
.name = "mt9p031",
|
|
|
|
},
|
2023-05-14 20:04:07 +08:00
|
|
|
.probe = mt9p031_probe,
|
2011-06-20 19:21:16 +08:00
|
|
|
.remove = mt9p031_remove,
|
|
|
|
.id_table = mt9p031_id,
|
|
|
|
};
|
|
|
|
|
2012-02-12 17:56:32 +08:00
|
|
|
module_i2c_driver(mt9p031_i2c_driver);
|
2011-06-20 19:21:16 +08:00
|
|
|
|
|
|
|
MODULE_DESCRIPTION("Aptina MT9P031 Camera driver");
|
|
|
|
MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
|
|
|
|
MODULE_LICENSE("GPL v2");
|