media: pxa_camera: Use the new set_mbus_config op
Move the PXA camera driver to use the new set_mbus_config pad operation. For this platform the change is not only cosmetic, as the pxa driver is currently the only driver in mainline to make use of the g_mbus_config and s_mbus_config video operations. The existing driver semantic is the following: - Collect all supported mbus config flags from the remote end - Match them with the supported PXA mbus configuration flags - If the remote subdevice allows multiple options for for VSYNC, HSYNC and PCLK polarity, use platform data requested settings The semantic of the new get_mbus_config and set_mbus_config differs from the corresponding video ops, particularly in the fact get_mbus_config reports the current mbus configuration and not the set of supported configuration options, with set_mbus_config always reporting the actual mbus configuration applied to the remote subdevice. Adapt the driver to perform the following - Set the remote subdevice mbus configuration according to the PXA platform data preferences. - If the applied configuration differs from the requested one (i.e. the remote subdevice does not allow changing one setting) make sure that - The remote end does not claim for DATA_ACTIVE_LOW, which seems not supported by the platform - The bus mastering roles match While at there remove a few checks performed on the media bus configuration at get_format() time as they do not belong there. Compile-tested only. Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
parent
2d26e44098
commit
ebb965acdd
|
@ -605,42 +605,6 @@ static const struct pxa_mbus_pixelfmt *pxa_mbus_get_fmtdesc(
|
||||||
return pxa_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
|
return pxa_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int pxa_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
|
|
||||||
unsigned int flags)
|
|
||||||
{
|
|
||||||
unsigned long common_flags;
|
|
||||||
bool hsync = true, vsync = true, pclk, data, mode;
|
|
||||||
bool mipi_lanes, mipi_clock;
|
|
||||||
|
|
||||||
common_flags = cfg->flags & flags;
|
|
||||||
|
|
||||||
switch (cfg->type) {
|
|
||||||
case V4L2_MBUS_PARALLEL:
|
|
||||||
hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH |
|
|
||||||
V4L2_MBUS_HSYNC_ACTIVE_LOW);
|
|
||||||
vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH |
|
|
||||||
V4L2_MBUS_VSYNC_ACTIVE_LOW);
|
|
||||||
/* fall through */
|
|
||||||
case V4L2_MBUS_BT656:
|
|
||||||
pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING |
|
|
||||||
V4L2_MBUS_PCLK_SAMPLE_FALLING);
|
|
||||||
data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH |
|
|
||||||
V4L2_MBUS_DATA_ACTIVE_LOW);
|
|
||||||
mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE);
|
|
||||||
return (!hsync || !vsync || !pclk || !data || !mode) ?
|
|
||||||
0 : common_flags;
|
|
||||||
case V4L2_MBUS_CSI2_DPHY:
|
|
||||||
mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES;
|
|
||||||
mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK |
|
|
||||||
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK);
|
|
||||||
return (!mipi_lanes || !mipi_clock) ? 0 : common_flags;
|
|
||||||
default:
|
|
||||||
WARN_ON(1);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct pxa_camera_format_xlate - match between host and sensor formats
|
* struct pxa_camera_format_xlate - match between host and sensor formats
|
||||||
* @code: code of a sensor provided format
|
* @code: code of a sensor provided format
|
||||||
|
@ -1231,31 +1195,6 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_platform_param(struct pxa_camera_dev *pcdev,
|
|
||||||
unsigned char buswidth, unsigned long *flags)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Platform specified synchronization and pixel clock polarities are
|
|
||||||
* only a recommendation and are only used during probing. The PXA270
|
|
||||||
* quick capture interface supports both.
|
|
||||||
*/
|
|
||||||
*flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
|
|
||||||
V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) |
|
|
||||||
V4L2_MBUS_HSYNC_ACTIVE_HIGH |
|
|
||||||
V4L2_MBUS_HSYNC_ACTIVE_LOW |
|
|
||||||
V4L2_MBUS_VSYNC_ACTIVE_HIGH |
|
|
||||||
V4L2_MBUS_VSYNC_ACTIVE_LOW |
|
|
||||||
V4L2_MBUS_DATA_ACTIVE_HIGH |
|
|
||||||
V4L2_MBUS_PCLK_SAMPLE_RISING |
|
|
||||||
V4L2_MBUS_PCLK_SAMPLE_FALLING;
|
|
||||||
|
|
||||||
/* If requested data width is supported by the platform, use it */
|
|
||||||
if ((1 << (buswidth - 1)) & pcdev->width_flags)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pxa_camera_setup_cicr(struct pxa_camera_dev *pcdev,
|
static void pxa_camera_setup_cicr(struct pxa_camera_dev *pcdev,
|
||||||
unsigned long flags, __u32 pixfmt)
|
unsigned long flags, __u32 pixfmt)
|
||||||
{
|
{
|
||||||
|
@ -1598,99 +1537,78 @@ static int pxa_camera_init_videobuf2(struct pxa_camera_dev *pcdev)
|
||||||
*/
|
*/
|
||||||
static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev)
|
static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev)
|
||||||
{
|
{
|
||||||
|
unsigned int bus_width = pcdev->current_fmt->host_fmt->bits_per_sample;
|
||||||
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
|
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
|
||||||
u32 pixfmt = pcdev->current_fmt->host_fmt->fourcc;
|
u32 pixfmt = pcdev->current_fmt->host_fmt->fourcc;
|
||||||
unsigned long bus_flags, common_flags;
|
int mbus_config;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = test_platform_param(pcdev,
|
if (!((1 << (bus_width - 1)) & pcdev->width_flags)) {
|
||||||
pcdev->current_fmt->host_fmt->bits_per_sample,
|
dev_err(pcdev_to_dev(pcdev), "Unsupported bus width %u",
|
||||||
&bus_flags);
|
bus_width);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = sensor_call(pcdev, video, g_mbus_config, &cfg);
|
|
||||||
if (!ret) {
|
|
||||||
common_flags = pxa_mbus_config_compatible(&cfg,
|
|
||||||
bus_flags);
|
|
||||||
if (!common_flags) {
|
|
||||||
dev_warn(pcdev_to_dev(pcdev),
|
|
||||||
"Flags incompatible: camera 0x%x, host 0x%lx\n",
|
|
||||||
cfg.flags, bus_flags);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
} else if (ret != -ENOIOCTLCMD) {
|
|
||||||
return ret;
|
|
||||||
} else {
|
|
||||||
common_flags = bus_flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
pcdev->channels = 1;
|
pcdev->channels = 1;
|
||||||
|
|
||||||
/* Make choices, based on platform preferences */
|
/* Make choices, based on platform preferences */
|
||||||
if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
|
mbus_config = 0;
|
||||||
(common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
|
if (pcdev->platform_flags & PXA_CAMERA_MASTER)
|
||||||
|
mbus_config |= V4L2_MBUS_MASTER;
|
||||||
|
else
|
||||||
|
mbus_config |= V4L2_MBUS_SLAVE;
|
||||||
|
|
||||||
if (pcdev->platform_flags & PXA_CAMERA_HSP)
|
if (pcdev->platform_flags & PXA_CAMERA_HSP)
|
||||||
common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
|
mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_HIGH;
|
||||||
else
|
else
|
||||||
common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
|
mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_LOW;
|
||||||
}
|
|
||||||
|
|
||||||
if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
|
|
||||||
(common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
|
|
||||||
if (pcdev->platform_flags & PXA_CAMERA_VSP)
|
if (pcdev->platform_flags & PXA_CAMERA_VSP)
|
||||||
common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
|
mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_HIGH;
|
||||||
else
|
else
|
||||||
common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
|
mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_LOW;
|
||||||
}
|
|
||||||
|
|
||||||
if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
|
|
||||||
(common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
|
|
||||||
if (pcdev->platform_flags & PXA_CAMERA_PCP)
|
if (pcdev->platform_flags & PXA_CAMERA_PCP)
|
||||||
common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
|
mbus_config |= V4L2_MBUS_PCLK_SAMPLE_RISING;
|
||||||
else
|
else
|
||||||
common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
|
mbus_config |= V4L2_MBUS_PCLK_SAMPLE_FALLING;
|
||||||
}
|
mbus_config |= V4L2_MBUS_DATA_ACTIVE_HIGH;
|
||||||
|
|
||||||
cfg.flags = common_flags;
|
cfg.flags = mbus_config;
|
||||||
ret = sensor_call(pcdev, video, s_mbus_config, &cfg);
|
ret = sensor_call(pcdev, pad, set_mbus_config, 0, &cfg);
|
||||||
if (ret < 0 && ret != -ENOIOCTLCMD) {
|
if (ret < 0 && ret != -ENOIOCTLCMD) {
|
||||||
dev_dbg(pcdev_to_dev(pcdev),
|
dev_err(pcdev_to_dev(pcdev),
|
||||||
"camera s_mbus_config(0x%lx) returned %d\n",
|
"Failed to call set_mbus_config: %d\n", ret);
|
||||||
common_flags, ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxa_camera_setup_cicr(pcdev, common_flags, pixfmt);
|
/*
|
||||||
|
* If the requested media bus configuration has not been fully applied
|
||||||
return 0;
|
* make sure it is supported by the platform.
|
||||||
}
|
*
|
||||||
|
* PXA does not support V4L2_MBUS_DATA_ACTIVE_LOW and the bus mastering
|
||||||
static int pxa_camera_try_bus_param(struct pxa_camera_dev *pcdev,
|
* roles should match.
|
||||||
unsigned char buswidth)
|
*/
|
||||||
{
|
if (cfg.flags != mbus_config) {
|
||||||
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
|
unsigned int pxa_mbus_role = mbus_config & (V4L2_MBUS_MASTER |
|
||||||
unsigned long bus_flags, common_flags;
|
V4L2_MBUS_SLAVE);
|
||||||
int ret = test_platform_param(pcdev, buswidth, &bus_flags);
|
if (pxa_mbus_role != (cfg.flags & (V4L2_MBUS_MASTER |
|
||||||
|
V4L2_MBUS_SLAVE))) {
|
||||||
if (ret < 0)
|
dev_err(pcdev_to_dev(pcdev),
|
||||||
return ret;
|
"Unsupported mbus configuration: bus mastering\n");
|
||||||
|
return -EINVAL;
|
||||||
ret = sensor_call(pcdev, video, g_mbus_config, &cfg);
|
}
|
||||||
if (!ret) {
|
|
||||||
common_flags = pxa_mbus_config_compatible(&cfg,
|
if (cfg.flags & V4L2_MBUS_DATA_ACTIVE_LOW) {
|
||||||
bus_flags);
|
dev_err(pcdev_to_dev(pcdev),
|
||||||
if (!common_flags) {
|
"Unsupported mbus configuration: DATA_ACTIVE_LOW\n");
|
||||||
dev_warn(pcdev_to_dev(pcdev),
|
|
||||||
"Flags incompatible: camera 0x%x, host 0x%lx\n",
|
|
||||||
cfg.flags, bus_flags);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
} else if (ret == -ENOIOCTLCMD) {
|
|
||||||
ret = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
pxa_camera_setup_cicr(pcdev, cfg.flags, pixfmt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pxa_mbus_pixelfmt pxa_camera_formats[] = {
|
static const struct pxa_mbus_pixelfmt pxa_camera_formats[] = {
|
||||||
|
@ -1738,11 +1656,6 @@ static int pxa_camera_get_formats(struct v4l2_device *v4l2_dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This also checks support for the requested bits-per-sample */
|
|
||||||
ret = pxa_camera_try_bus_param(pcdev, fmt->bits_per_sample);
|
|
||||||
if (ret < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch (code.code) {
|
switch (code.code) {
|
||||||
case MEDIA_BUS_FMT_UYVY8_2X8:
|
case MEDIA_BUS_FMT_UYVY8_2X8:
|
||||||
formats++;
|
formats++;
|
||||||
|
|
Loading…
Reference in New Issue