Devicetree
 help / color / mirror / Atom feed
* Applied "ASoC: soc-core: adjust for graph on snd_soc_of_parse_card_name" to the asoc tree
From: Mark Brown @ 2016-11-11 15:28 UTC (permalink / raw)
  To: Kuninori Morimoto; +Cc: Mark Brown, Rob Herring
In-Reply-To: <87mvi34c51.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>

The patch

   ASoC: soc-core: adjust for graph on snd_soc_of_parse_card_name

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 8f5ebb1bee15b5720741a98414767bb86f6c2b23 Mon Sep 17 00:00:00 2001
From: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
Date: Fri, 11 Nov 2016 01:17:27 +0000
Subject: [PATCH] ASoC: soc-core: adjust for graph on
 snd_soc_of_parse_card_name

It is assuming that the card related information is located on
"card" node, but graph case doesn't have it.
This patch adds node parameter to adjust for graph support

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
 include/sound/soc.h  |  7 +++++--
 sound/soc/soc-core.c | 11 ++++++-----
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/include/sound/soc.h b/include/sound/soc.h
index 346223b38e0d..8457aab9eab0 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1642,8 +1642,11 @@ static inline struct snd_soc_platform *snd_soc_kcontrol_platform(
 int snd_soc_util_init(void);
 void snd_soc_util_exit(void);
 
-int snd_soc_of_parse_card_name(struct snd_soc_card *card,
-			       const char *propname);
+#define snd_soc_of_parse_card_name(card, propname) \
+	snd_soc_of_parse_card_name_from_node(card, NULL, propname)
+int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card,
+					 struct device_node *np,
+					 const char *propname);
 int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
 					  const char *propname);
 int snd_soc_of_parse_tdm_slot(struct device_node *np,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index e4c90806fa10..17132fb57930 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3424,10 +3424,10 @@ void snd_soc_unregister_codec(struct device *dev)
 EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
 
 /* Retrieve a card's name from device tree */
-int snd_soc_of_parse_card_name(struct snd_soc_card *card,
-			       const char *propname)
+int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card,
+					 struct device_node *np,
+					 const char *propname)
 {
-	struct device_node *np;
 	int ret;
 
 	if (!card->dev) {
@@ -3435,7 +3435,8 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
 		return -EINVAL;
 	}
 
-	np = card->dev->of_node;
+	if (!np)
+		np = card->dev->of_node;
 
 	ret = of_property_read_string_index(np, propname, 0, &card->name);
 	/*
@@ -3452,7 +3453,7 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name);
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name_from_node);
 
 static const struct snd_soc_dapm_widget simple_widgets[] = {
 	SND_SOC_DAPM_MIC("Microphone", NULL),
-- 
2.10.2

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Applied "ASoC: soc-core: adjust for graph on snd_soc_of_parse_audio_simple_widgets" to the asoc tree
From: Mark Brown @ 2016-11-11 15:28 UTC (permalink / raw)
  To: Kuninori Morimoto; +Cc: Mark Brown, Rob Herring
In-Reply-To: <87lgxn4c4k.wl%kuninori.morimoto.gx@renesas.com>

The patch

   ASoC: soc-core: adjust for graph on snd_soc_of_parse_audio_simple_widgets

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 1ef5bcd57be5c8b31286b7b47828064be25f266b Mon Sep 17 00:00:00 2001
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Date: Fri, 11 Nov 2016 01:18:08 +0000
Subject: [PATCH] ASoC: soc-core: adjust for graph on
 snd_soc_of_parse_audio_simple_widgets

It is assuming that the card related information is located on
"card" node, but graph case doesn't have it.
This patch adds node parameter to adjust for graph support

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 include/sound/soc.h  | 8 ++++++--
 sound/soc/soc-core.c | 9 ++++++---
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/include/sound/soc.h b/include/sound/soc.h
index 8457aab9eab0..77b01c45ee8d 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1647,8 +1647,12 @@ void snd_soc_util_exit(void);
 int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card,
 					 struct device_node *np,
 					 const char *propname);
-int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
-					  const char *propname);
+#define snd_soc_of_parse_audio_simple_widgets(card, propname)\
+	snd_soc_of_parse_audio_simple_widgets_from_node(card, NULL, propname)
+int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card,
+						    struct device_node *np,
+						    const char *propname);
+
 int snd_soc_of_parse_tdm_slot(struct device_node *np,
 			      unsigned int *tx_mask,
 			      unsigned int *rx_mask,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 17132fb57930..6f911f4d413a 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3462,14 +3462,17 @@ static const struct snd_soc_dapm_widget simple_widgets[] = {
 	SND_SOC_DAPM_SPK("Speaker", NULL),
 };
 
-int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
+int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card,
+					  struct device_node *np,
 					  const char *propname)
 {
-	struct device_node *np = card->dev->of_node;
 	struct snd_soc_dapm_widget *widgets;
 	const char *template, *wname;
 	int i, j, num_widgets, ret;
 
+	if (!np)
+		np = card->dev->of_node;
+
 	num_widgets = of_property_count_strings(np, propname);
 	if (num_widgets < 0) {
 		dev_err(card->dev,
@@ -3540,7 +3543,7 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets_from_node);
 
 static int snd_soc_of_get_slot_mask(struct device_node *np,
 				    const char *prop_name,
-- 
2.10.2

^ permalink raw reply related

* Re: [PATCH v5 2/3] vcodec: mediatek: Add Mediatek JPEG Decoder Driver
From: Hans Verkuil @ 2016-11-11 15:10 UTC (permalink / raw)
  To: Rick Chang, Hans Verkuil, Laurent Pinchart, Mauro Carvalho Chehab,
	Matthias Brugger, Rob Herring
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	srv_heupstream-NuS5LvNUpcJWk0Htik3J/w,
	linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Minghsiu Tsai
In-Reply-To: <1478586880-3923-3-git-send-email-rick.chang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>

A quick review:

On 11/08/2016 07:34 AM, Rick Chang wrote:
> Add v4l2 driver for Mediatek JPEG Decoder
> 
> Signed-off-by: Rick Chang <rick.chang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> Signed-off-by: Minghsiu Tsai <minghsiu.tsai-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> ---
>  drivers/media/platform/Kconfig                   |   15 +
>  drivers/media/platform/Makefile                  |    2 +
>  drivers/media/platform/mtk-jpeg/Makefile         |    2 +
>  drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c  | 1275 ++++++++++++++++++++++
>  drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h  |  141 +++
>  drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c    |  417 +++++++
>  drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h    |   91 ++
>  drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c |  160 +++
>  drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h |   25 +
>  drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h   |   58 +
>  10 files changed, 2186 insertions(+)
>  create mode 100644 drivers/media/platform/mtk-jpeg/Makefile
>  create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
>  create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h
>  create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c
>  create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h
>  create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c
>  create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h
>  create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h
> 
> diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> index 754edbf1..96c9887 100644
> --- a/drivers/media/platform/Kconfig
> +++ b/drivers/media/platform/Kconfig
> @@ -162,6 +162,21 @@ config VIDEO_CODA
>  	   Coda is a range of video codec IPs that supports
>  	   H.264, MPEG-4, and other video formats.
>  
> +config VIDEO_MEDIATEK_JPEG
> +	tristate "Mediatek JPEG Codec driver"
> +	depends on MTK_IOMMU_V1 || COMPILE_TEST
> +	depends on VIDEO_DEV && VIDEO_V4L2
> +	depends on ARCH_MEDIATEK || COMPILE_TEST
> +	depends on HAS_DMA
> +	select VIDEOBUF2_DMA_CONTIG
> +	select V4L2_MEM2MEM_DEV
> +	---help---
> +	  Mediatek jpeg codec driver provides HW capability to decode
> +	  JPEG format
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called mtk-jpeg
> +
>  config VIDEO_MEDIATEK_VPU
>  	tristate "Mediatek Video Processor Unit"
>  	depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
> diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> index f842933..cf701e3 100644
> --- a/drivers/media/platform/Makefile
> +++ b/drivers/media/platform/Makefile
> @@ -68,3 +68,5 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VPU)	+= mtk-vpu/
>  obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC)	+= mtk-vcodec/
>  
>  obj-$(CONFIG_VIDEO_MEDIATEK_MDP)	+= mtk-mdp/
> +
> +obj-$(CONFIG_VIDEO_MEDIATEK_JPEG)	+= mtk-jpeg/
> diff --git a/drivers/media/platform/mtk-jpeg/Makefile b/drivers/media/platform/mtk-jpeg/Makefile
> new file mode 100644
> index 0000000..b2e6069
> --- /dev/null
> +++ b/drivers/media/platform/mtk-jpeg/Makefile
> @@ -0,0 +1,2 @@
> +mtk_jpeg-objs := mtk_jpeg_core.o mtk_jpeg_hw.o mtk_jpeg_parse.o
> +obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk_jpeg.o
> diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
> new file mode 100644
> index 0000000..33ddf79
> --- /dev/null
> +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
> @@ -0,0 +1,1275 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Ming Hsiu Tsai <minghsiu.tsai-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> + *         Rick Chang <rick.chang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/spinlock.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-mem2mem.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/videobuf2-core.h>
> +#include <media/videobuf2-dma-contig.h>
> +#include <soc/mediatek/smi.h>
> +#include <asm/dma-iommu.h>
> +
> +#include "mtk_jpeg_hw.h"
> +#include "mtk_jpeg_core.h"
> +#include "mtk_jpeg_parse.h"
> +
> +static struct mtk_jpeg_fmt mtk_jpeg_formats[] = {
> +	{
> +		.name		= "JPEG JFIF",
> +		.fourcc		= V4L2_PIX_FMT_JPEG,
> +		.colplanes	= 1,
> +		.flags		= MTK_JPEG_FMT_FLAG_DEC_OUTPUT,
> +	},
> +	{
> +		.name		= "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
> +		.fourcc		= V4L2_PIX_FMT_YUV420M,
> +		.h_sample	= {4, 2, 2},
> +		.v_sample	= {4, 2, 2},
> +		.colplanes	= 3,
> +		.h_align	= 5,
> +		.v_align	= 4,
> +		.flags		= MTK_JPEG_FMT_FLAG_DEC_CAPTURE,
> +	},
> +	{
> +		.name		= "YUV 4:2:2 non-contiguous 3-planar, Y/Cb/Cr",
> +		.fourcc		= V4L2_PIX_FMT_YUV422M,
> +		.h_sample	= {4, 2, 2},
> +		.v_sample	= {4, 4, 4},
> +		.colplanes	= 3,
> +		.h_align	= 5,
> +		.v_align	= 3,
> +		.flags		= MTK_JPEG_FMT_FLAG_DEC_CAPTURE,

You probably don't need the name since it is filled in by the v4l2 core
(v4l2-ioctls.c).

> +	},
> +};
> +
> +#define MTK_JPEG_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_formats)
> +
> +enum {
> +	MTK_JPEG_BUF_FLAGS_INIT			= 0,
> +	MTK_JPEG_BUF_FLAGS_LAST_FRAME		= 1,
> +};
> +
> +struct mtk_jpeg_src_buf {
> +	struct vb2_v4l2_buffer b;
> +	struct list_head list;
> +	int flags;
> +	struct mtk_jpeg_dec_param dec_param;
> +};
> +
> +static int debug;
> +module_param(debug, int, 0644);
> +
> +static inline struct mtk_jpeg_ctx *mtk_jpeg_fh_to_ctx(struct v4l2_fh *fh)
> +{
> +	return container_of(fh, struct mtk_jpeg_ctx, fh);
> +}
> +
> +static inline struct mtk_jpeg_src_buf *mtk_jpeg_vb2_to_srcbuf(
> +							struct vb2_buffer *vb)
> +{
> +	return container_of(to_vb2_v4l2_buffer(vb), struct mtk_jpeg_src_buf, b);
> +}
> +
> +static int mtk_jpeg_querycap(struct file *file, void *priv,
> +			     struct v4l2_capability *cap)
> +{
> +	struct mtk_jpeg_dev *jpeg = video_drvdata(file);
> +
> +	strlcpy(cap->driver, MTK_JPEG_NAME " decoder", sizeof(cap->driver));
> +	strlcpy(cap->card, MTK_JPEG_NAME " decoder", sizeof(cap->card));
> +	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
> +		 dev_name(jpeg->dev));
> +
> +	return 0;
> +}
> +
> +static int mtk_jpeg_enum_fmt(struct mtk_jpeg_fmt *mtk_jpeg_formats, int n,
> +			     struct v4l2_fmtdesc *f, u32 type)
> +{
> +	int i, num = 0;
> +
> +	for (i = 0; i < n; ++i) {
> +		if (mtk_jpeg_formats[i].flags & type) {
> +			if (num == f->index)
> +				break;
> +			++num;
> +		}
> +	}
> +
> +	if (i >= n)
> +		return -EINVAL;
> +
> +	f->pixelformat = mtk_jpeg_formats[i].fourcc;
> +
> +	return 0;
> +}
> +
> +static int mtk_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
> +				     struct v4l2_fmtdesc *f)
> +{
> +	return mtk_jpeg_enum_fmt(mtk_jpeg_formats, MTK_JPEG_NUM_FORMATS, f,
> +				 MTK_JPEG_FMT_FLAG_DEC_CAPTURE);
> +}
> +
> +static int mtk_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
> +				     struct v4l2_fmtdesc *f)
> +{
> +	return mtk_jpeg_enum_fmt(mtk_jpeg_formats, MTK_JPEG_NUM_FORMATS, f,
> +				 MTK_JPEG_FMT_FLAG_DEC_OUTPUT);
> +}
> +
> +static struct mtk_jpeg_q_data *mtk_jpeg_get_q_data(struct mtk_jpeg_ctx *ctx,
> +						   enum v4l2_buf_type type)
> +{
> +	if (V4L2_TYPE_IS_OUTPUT(type))
> +		return &ctx->out_q;
> +	else

No need for 'else'.

> +		return &ctx->cap_q;
> +}
> +
> +static struct mtk_jpeg_fmt *mtk_jpeg_find_format(struct mtk_jpeg_ctx *ctx,
> +						 u32 pixelformat,
> +						 unsigned int fmt_type)
> +{
> +	unsigned int k, fmt_flag;
> +
> +	fmt_flag = (fmt_type == MTK_JPEG_FMT_TYPE_OUTPUT) ?
> +		   MTK_JPEG_FMT_FLAG_DEC_OUTPUT :
> +		   MTK_JPEG_FMT_FLAG_DEC_CAPTURE;
> +
> +	for (k = 0; k < MTK_JPEG_NUM_FORMATS; k++) {
> +		struct mtk_jpeg_fmt *fmt = &mtk_jpeg_formats[k];
> +
> +		if (fmt->fourcc == pixelformat && fmt->flags & fmt_flag)
> +			return fmt;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void mtk_jpeg_bound_align_image(u32 *w, unsigned int wmin,
> +				       unsigned int wmax, unsigned int walign,
> +				       u32 *h, unsigned int hmin,
> +				       unsigned int hmax, unsigned int halign)
> +{
> +	int width, height, w_step, h_step;
> +
> +	width = *w;
> +	height = *h;
> +	w_step = 1 << walign;
> +	h_step = 1 << halign;
> +
> +	v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
> +	if (*w < width && (*w + w_step) <= wmax)
> +		*w += w_step;
> +	if (*h < height && (*h + h_step) <= hmax)
> +		*h += h_step;
> +}
> +
> +static void mtk_jpeg_adjust_fmt_mplane(struct mtk_jpeg_ctx *ctx,
> +				       struct v4l2_format *f)
> +{
> +	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> +	struct mtk_jpeg_q_data *q_data;
> +	int i;
> +
> +	q_data = mtk_jpeg_get_q_data(ctx, f->type);
> +
> +	pix_mp->width = q_data->w;
> +	pix_mp->height = q_data->h;
> +	pix_mp->pixelformat = q_data->fmt->fourcc;
> +	pix_mp->num_planes = q_data->fmt->colplanes;
> +
> +	for (i = 0; i < pix_mp->num_planes; i++) {
> +		pix_mp->plane_fmt[i].bytesperline = q_data->bytesperline[i];
> +		pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
> +	}
> +}
> +
> +static int mtk_jpeg_try_fmt_mplane(struct v4l2_format *f,
> +				   struct mtk_jpeg_fmt *fmt,
> +				   struct mtk_jpeg_ctx *ctx, int q_type)
> +{
> +	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> +	int i;
> +
> +	memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
> +	pix_mp->field = V4L2_FIELD_NONE;
> +
> +	if (ctx->state != MTK_JPEG_INIT) {
> +		mtk_jpeg_adjust_fmt_mplane(ctx, f);
> +		goto end;
> +	}
> +
> +	pix_mp->num_planes = fmt->colplanes;
> +	pix_mp->pixelformat = fmt->fourcc;
> +
> +	if (q_type == MTK_JPEG_FMT_TYPE_OUTPUT) {
> +		struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0];
> +
> +		mtk_jpeg_bound_align_image(&pix_mp->width, MTK_JPEG_MIN_WIDTH,
> +					   MTK_JPEG_MAX_WIDTH, 0,
> +					   &pix_mp->height, MTK_JPEG_MIN_HEIGHT,
> +					   MTK_JPEG_MAX_HEIGHT, 0);
> +
> +		memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
> +		pfmt->bytesperline = 0;
> +		/* Source size must be aligned to 128 */
> +		pfmt->sizeimage = mtk_jpeg_align(pfmt->sizeimage, 128);
> +		if (pfmt->sizeimage == 0)
> +			pfmt->sizeimage = MTK_JPEG_DEFAULT_SIZEIMAGE;
> +		goto end;
> +	}
> +
> +	/* type is MTK_JPEG_FMT_TYPE_CAPTURE */
> +	mtk_jpeg_bound_align_image(&pix_mp->width, MTK_JPEG_MIN_WIDTH,
> +				   MTK_JPEG_MAX_WIDTH, fmt->h_align,
> +				   &pix_mp->height, MTK_JPEG_MIN_HEIGHT,
> +				   MTK_JPEG_MAX_HEIGHT, fmt->v_align);
> +
> +	for (i = 0; i < fmt->colplanes; i++) {
> +		struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[i];
> +		u32 stride = pix_mp->width * fmt->h_sample[i] / 4;
> +		u32 h = pix_mp->height * fmt->v_sample[i] / 4;
> +
> +		memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
> +		pfmt->bytesperline = stride;
> +		pfmt->sizeimage = stride * h;
> +	}
> +end:
> +	v4l2_dbg(2, debug, &jpeg->v4l2_dev, "wxh:%ux%u\n",
> +		 pix_mp->width, pix_mp->height);
> +	for (i = 0; i < pix_mp->num_planes; i++) {
> +		v4l2_dbg(2, debug, &jpeg->v4l2_dev,
> +			 "plane[%d] bpl=%u, size=%u\n",
> +			 i,
> +			 pix_mp->plane_fmt[i].bytesperline,
> +			 pix_mp->plane_fmt[i].sizeimage);
> +	}
> +	return 0;
> +}
> +
> +static int mtk_jpeg_g_fmt_vid_mplane(struct file *file, void *priv,
> +				     struct v4l2_format *f)
> +{
> +	struct vb2_queue *vq;
> +	struct mtk_jpeg_q_data *q_data = NULL;
> +	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> +	struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
> +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> +	int i;
> +
> +	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
> +	if (!vq)
> +		return -EINVAL;
> +
> +	q_data = mtk_jpeg_get_q_data(ctx, f->type);
> +
> +	memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
> +	pix_mp->width = q_data->w;
> +	pix_mp->height = q_data->h;
> +	pix_mp->field = V4L2_FIELD_NONE;
> +	pix_mp->pixelformat = q_data->fmt->fourcc;
> +	pix_mp->num_planes = q_data->fmt->colplanes;
> +	pix_mp->colorspace = ctx->colorspace;
> +	pix_mp->ycbcr_enc = ctx->ycbcr_enc;
> +	pix_mp->xfer_func = ctx->xfer_func;
> +	pix_mp->quantization = ctx->quantization;
> +
> +	v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) g_fmt:%s wxh:%ux%u\n",
> +		 f->type, q_data->fmt->name, pix_mp->width, pix_mp->height);
> +
> +	for (i = 0; i < pix_mp->num_planes; i++) {
> +		struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[i];
> +
> +		pfmt->bytesperline = q_data->bytesperline[i];
> +		pfmt->sizeimage = q_data->sizeimage[i];
> +		memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
> +
> +		v4l2_dbg(1, debug, &jpeg->v4l2_dev,
> +			 "plane[%d] bpl=%u, size=%u\n",
> +			 i,
> +			 pfmt->bytesperline,
> +			 pfmt->sizeimage);
> +	}
> +	return 0;
> +}
> +
> +static int mtk_jpeg_try_fmt_vid_cap_mplane(struct file *file, void *priv,
> +					   struct v4l2_format *f)
> +{
> +	struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
> +	struct mtk_jpeg_fmt *fmt;
> +
> +	fmt = mtk_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
> +				   MTK_JPEG_FMT_TYPE_CAPTURE);
> +	if (!fmt)
> +		fmt = ctx->cap_q.fmt;
> +
> +	v4l2_dbg(2, debug, &ctx->jpeg->v4l2_dev, "(%d) try_fmt:%s\n",
> +		 f->type, fmt->name);
> +
> +	return mtk_jpeg_try_fmt_mplane(f, fmt, ctx, MTK_JPEG_FMT_TYPE_CAPTURE);
> +}
> +
> +static int mtk_jpeg_try_fmt_vid_out_mplane(struct file *file, void *priv,
> +					   struct v4l2_format *f)
> +{
> +	struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
> +	struct mtk_jpeg_fmt *fmt;
> +
> +	fmt = mtk_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
> +				   MTK_JPEG_FMT_TYPE_OUTPUT);
> +	if (!fmt)
> +		fmt = ctx->out_q.fmt;
> +
> +	v4l2_dbg(2, debug, &ctx->jpeg->v4l2_dev, "(%d) try_fmt:%s\n",
> +		 f->type, fmt->name);
> +
> +	return mtk_jpeg_try_fmt_mplane(f, fmt, ctx, MTK_JPEG_FMT_TYPE_OUTPUT);
> +}
> +
> +static int mtk_jpeg_s_fmt_mplane(struct mtk_jpeg_ctx *ctx,
> +				 struct v4l2_format *f)
> +{
> +	struct vb2_queue *vq;
> +	struct mtk_jpeg_q_data *q_data = NULL;
> +	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> +	unsigned int f_type;
> +	int i;
> +
> +	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
> +	if (!vq)
> +		return -EINVAL;
> +
> +	q_data = mtk_jpeg_get_q_data(ctx, f->type);
> +
> +	if (vb2_is_busy(vq)) {
> +		v4l2_err(&jpeg->v4l2_dev, "queue busy\n");
> +		return -EBUSY;
> +	}
> +
> +	f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
> +			 MTK_JPEG_FMT_TYPE_OUTPUT : MTK_JPEG_FMT_TYPE_CAPTURE;
> +
> +	q_data->fmt = mtk_jpeg_find_format(ctx, pix_mp->pixelformat, f_type);
> +	q_data->w = pix_mp->width;
> +	q_data->h = pix_mp->height;
> +	ctx->colorspace = pix_mp->colorspace;
> +	ctx->ycbcr_enc = pix_mp->ycbcr_enc;
> +	ctx->xfer_func = pix_mp->xfer_func;
> +	ctx->quantization = pix_mp->quantization;
> +
> +	v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) s_fmt:%s wxh:%ux%u\n",
> +		 f->type, q_data->fmt->name, q_data->w, q_data->h);
> +
> +	for (i = 0; i < q_data->fmt->colplanes; i++) {
> +		q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline;
> +		q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage;
> +
> +		v4l2_dbg(1, debug, &jpeg->v4l2_dev,
> +			 "plane[%d] bpl=%u, size=%u\n",
> +			 i, q_data->bytesperline[i], q_data->sizeimage[i]);
> +	}
> +
> +	return 0;
> +}
> +
> +static int mtk_jpeg_s_fmt_vid_out_mplane(struct file *file, void *priv,
> +					 struct v4l2_format *f)
> +{
> +	int ret;
> +
> +	ret = mtk_jpeg_try_fmt_vid_out_mplane(file, priv, f);
> +	if (ret)
> +		return ret;
> +
> +	return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f);
> +}
> +
> +static int mtk_jpeg_s_fmt_vid_cap_mplane(struct file *file, void *priv,
> +					 struct v4l2_format *f)
> +{
> +	int ret;
> +
> +	ret = mtk_jpeg_try_fmt_vid_cap_mplane(file, priv, f);
> +	if (ret)
> +		return ret;
> +
> +	return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f);
> +}
> +
> +static void mtk_jpeg_queue_src_chg_event(struct mtk_jpeg_ctx *ctx)
> +{
> +	static const struct v4l2_event ev_src_ch = {
> +		.type = V4L2_EVENT_SOURCE_CHANGE,
> +		.u.src_change.changes =
> +		V4L2_EVENT_SRC_CH_RESOLUTION,
> +	};
> +
> +	v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
> +}
> +
> +static int mtk_jpeg_subscribe_event(struct v4l2_fh *fh,
> +				    const struct v4l2_event_subscription *sub)
> +{
> +	switch (sub->type) {
> +	case V4L2_EVENT_SOURCE_CHANGE:
> +		return v4l2_src_change_event_subscribe(fh, sub);
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int mtk_jpeg_g_selection(struct file *file, void *priv,
> +				struct v4l2_selection *s)
> +{
> +	struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
> +
> +	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +		return -EINVAL;
> +
> +	switch (s->target) {
> +	case V4L2_SEL_TGT_COMPOSE:
> +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> +		s->r.width = ctx->out_q.w;
> +		s->r.height = ctx->out_q.h;
> +		s->r.left = 0;
> +		s->r.top = 0;
> +		break;
> +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> +	case V4L2_SEL_TGT_COMPOSE_PADDED:
> +		s->r.width = ctx->cap_q.w;
> +		s->r.height = ctx->cap_q.h;
> +		s->r.left = 0;
> +		s->r.top = 0;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +static int mtk_jpeg_s_selection(struct file *file, void *priv,
> +				struct v4l2_selection *s)
> +{
> +	struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
> +
> +	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +		return -EINVAL;
> +
> +	switch (s->target) {
> +	case V4L2_SEL_TGT_COMPOSE:
> +		s->r.left = 0;
> +		s->r.top = 0;
> +		s->r.width = ctx->out_q.w;
> +		s->r.height = ctx->out_q.h;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
> +{
> +	struct v4l2_fh *fh = file->private_data;
> +	struct vb2_queue *vq;
> +	struct vb2_buffer *vb;
> +	struct mtk_jpeg_src_buf *jpeg_src_buf;
> +
> +	if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> +		goto end;
> +
> +	vq = v4l2_m2m_get_vq(fh->m2m_ctx, buf->type);
> +	vb = vq->bufs[buf->index];
> +	jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
> +	jpeg_src_buf->flags = (buf->m.planes[0].bytesused == 0) ?
> +		MTK_JPEG_BUF_FLAGS_LAST_FRAME : MTK_JPEG_BUF_FLAGS_INIT;
> +end:
> +	return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf);
> +}
> +
> +static const struct v4l2_ioctl_ops mtk_jpeg_ioctl_ops = {
> +	.vidioc_querycap                = mtk_jpeg_querycap,
> +	.vidioc_enum_fmt_vid_cap_mplane = mtk_jpeg_enum_fmt_vid_cap,
> +	.vidioc_enum_fmt_vid_out_mplane = mtk_jpeg_enum_fmt_vid_out,
> +	.vidioc_try_fmt_vid_cap_mplane	= mtk_jpeg_try_fmt_vid_cap_mplane,
> +	.vidioc_try_fmt_vid_out_mplane	= mtk_jpeg_try_fmt_vid_out_mplane,
> +	.vidioc_g_fmt_vid_cap_mplane    = mtk_jpeg_g_fmt_vid_mplane,
> +	.vidioc_g_fmt_vid_out_mplane    = mtk_jpeg_g_fmt_vid_mplane,
> +	.vidioc_s_fmt_vid_cap_mplane    = mtk_jpeg_s_fmt_vid_cap_mplane,
> +	.vidioc_s_fmt_vid_out_mplane    = mtk_jpeg_s_fmt_vid_out_mplane,
> +	.vidioc_qbuf                    = mtk_jpeg_qbuf,
> +	.vidioc_subscribe_event         = mtk_jpeg_subscribe_event,
> +	.vidioc_g_selection		= mtk_jpeg_g_selection,
> +	.vidioc_s_selection		= mtk_jpeg_s_selection,
> +
> +	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
> +	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
> +	.vidioc_reqbufs                 = v4l2_m2m_ioctl_reqbufs,
> +	.vidioc_querybuf                = v4l2_m2m_ioctl_querybuf,
> +	.vidioc_dqbuf                   = v4l2_m2m_ioctl_dqbuf,
> +	.vidioc_expbuf                  = v4l2_m2m_ioctl_expbuf,
> +	.vidioc_streamon                = v4l2_m2m_ioctl_streamon,
> +	.vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
> +
> +	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
> +};
> +
> +static int mtk_jpeg_queue_setup(struct vb2_queue *q,
> +				unsigned int *num_buffers,
> +				unsigned int *num_planes,
> +				unsigned int sizes[],
> +				struct device *alloc_ctxs[])
> +{
> +	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
> +	struct mtk_jpeg_q_data *q_data = NULL;
> +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> +	int i;
> +
> +	v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) buf_req count=%u\n",
> +		 q->type, *num_buffers);
> +
> +	q_data = mtk_jpeg_get_q_data(ctx, q->type);
> +	if (!q_data)
> +		return -EINVAL;
> +
> +	*num_planes = q_data->fmt->colplanes;
> +	for (i = 0; i < q_data->fmt->colplanes; i++) {
> +		sizes[i] = q_data->sizeimage[i];
> +		v4l2_dbg(1, debug, &jpeg->v4l2_dev, "sizeimage[%d]=%u\n",
> +			 i, sizes[i]);
> +	}
> +
> +	return 0;
> +}
> +
> +static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb)
> +{
> +	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> +	struct mtk_jpeg_q_data *q_data = NULL;
> +	int i;
> +
> +	q_data = mtk_jpeg_get_q_data(ctx, vb->vb2_queue->type);
> +	if (!q_data)
> +		return -EINVAL;
> +
> +	for (i = 0; i < q_data->fmt->colplanes; i++)
> +		vb2_set_plane_payload(vb, i, q_data->sizeimage[i]);
> +
> +	return 0;
> +}
> +
> +static bool mtk_jpeg_check_resolution_change(struct mtk_jpeg_ctx *ctx,
> +					     struct mtk_jpeg_dec_param *param)
> +{
> +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> +	struct mtk_jpeg_q_data *q_data;
> +
> +	q_data = &ctx->out_q;
> +	if (q_data->w != param->pic_w || q_data->h != param->pic_h) {
> +		v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Picture size change\n");
> +		return true;
> +	}
> +
> +	q_data = &ctx->cap_q;
> +	if (q_data->fmt != mtk_jpeg_find_format(ctx, param->dst_fourcc,
> +						MTK_JPEG_FMT_TYPE_CAPTURE)) {
> +		v4l2_dbg(1, debug, &jpeg->v4l2_dev, "format change\n");
> +		return true;
> +	}
> +	return false;
> +}
> +
> +static void mtk_jpeg_set_queue_data(struct mtk_jpeg_ctx *ctx,
> +				    struct mtk_jpeg_dec_param *param)
> +{
> +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> +	struct mtk_jpeg_q_data *q_data;
> +	int i;
> +
> +	q_data = &ctx->out_q;
> +	q_data->w = param->pic_w;
> +	q_data->h = param->pic_h;
> +
> +	q_data = &ctx->cap_q;
> +	q_data->w = param->dec_w;
> +	q_data->h = param->dec_h;
> +	q_data->fmt = mtk_jpeg_find_format(ctx,
> +					   param->dst_fourcc,
> +					   MTK_JPEG_FMT_TYPE_CAPTURE);
> +
> +	for (i = 0; i < q_data->fmt->colplanes; i++) {
> +		q_data->bytesperline[i] = param->mem_stride[i];
> +		q_data->sizeimage[i] = param->comp_size[i];
> +	}
> +
> +	v4l2_dbg(1, debug, &jpeg->v4l2_dev,
> +		 "set_parse cap:%s pic(%u, %u), buf(%u, %u)\n",
> +		 q_data->fmt->name, param->pic_w, param->pic_h,
> +		 param->dec_w, param->dec_h);
> +}
> +
> +static void mtk_jpeg_buf_queue(struct vb2_buffer *vb)
> +{
> +	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> +	struct mtk_jpeg_dec_param *param;
> +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> +	struct mtk_jpeg_src_buf *jpeg_src_buf;
> +	bool header_valid;
> +
> +	v4l2_dbg(2, debug, &jpeg->v4l2_dev, "(%d) buf_q id=%d, vb=%p",
> +		 vb->vb2_queue->type, vb->index, vb);
> +
> +	if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> +		goto end;
> +
> +	jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
> +	param = &jpeg_src_buf->dec_param;
> +	memset(param, 0, sizeof(*param));
> +
> +	if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) {
> +		v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Got eos");
> +		goto end;
> +	}
> +	header_valid = mtk_jpeg_parse(param, (u8 *)vb2_plane_vaddr(vb, 0),
> +				      vb2_get_plane_payload(vb, 0));
> +	if (!header_valid) {
> +		v4l2_err(&jpeg->v4l2_dev, "Header invalid.\n");
> +		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
> +		return;
> +	}
> +
> +	if (ctx->state == MTK_JPEG_INIT) {
> +		mtk_jpeg_queue_src_chg_event(ctx);
> +		mtk_jpeg_set_queue_data(ctx, param);
> +		ctx->state = MTK_JPEG_RUNNING;
> +	}
> +end:
> +	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, to_vb2_v4l2_buffer(vb));
> +}
> +
> +static void *mtk_jpeg_buf_remove(struct mtk_jpeg_ctx *ctx,
> +				 enum v4l2_buf_type type)
> +{
> +	if (V4L2_TYPE_IS_OUTPUT(type))
> +		return v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> +	else
> +		return v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> +}
> +
> +static int mtk_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
> +{
> +	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
> +	int ret = 0;
> +
> +	ret = pm_runtime_get_sync(ctx->jpeg->dev);
> +

If start_streaming returns an error, then you must call
v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_QUEUED) for all
buffers. Similar to what happens in stop_streaming, but with a different VB2_BUF_STATE.

> +	return ret > 0 ? 0 : ret;
> +}
> +
> +static void mtk_jpeg_stop_streaming(struct vb2_queue *q)
> +{
> +	struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
> +	struct vb2_buffer *vb;
> +
> +	/*
> +	 * STREAMOFF is an acknowledgment for source change event.
> +	 * Before STREAMOFF, we still have to return the old resolution and
> +	 * subsampling. Update capture queue when the stream is off.
> +	 */
> +	if (ctx->state == MTK_JPEG_SOURCE_CHANGE &&
> +	    !V4L2_TYPE_IS_OUTPUT(q->type)) {
> +		struct mtk_jpeg_src_buf *src_buf;
> +
> +		vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
> +		src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
> +		mtk_jpeg_set_queue_data(ctx, &src_buf->dec_param);
> +		ctx->state = MTK_JPEG_RUNNING;
> +	} else if (V4L2_TYPE_IS_OUTPUT(q->type)) {
> +		ctx->state = MTK_JPEG_INIT;
> +	}
> +
> +	vb = mtk_jpeg_buf_remove(ctx, q->type);
> +	while (vb) {
> +		v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR);
> +		vb = mtk_jpeg_buf_remove(ctx, q->type);
> +	}
> +
> +	pm_runtime_put_sync(ctx->jpeg->dev);
> +}
> +
> +static struct vb2_ops mtk_jpeg_qops = {
> +	.queue_setup        = mtk_jpeg_queue_setup,
> +	.buf_prepare        = mtk_jpeg_buf_prepare,
> +	.buf_queue          = mtk_jpeg_buf_queue,
> +	.wait_prepare       = vb2_ops_wait_prepare,
> +	.wait_finish        = vb2_ops_wait_finish,
> +	.start_streaming    = mtk_jpeg_start_streaming,
> +	.stop_streaming     = mtk_jpeg_stop_streaming,
> +};
> +
> +static void mtk_jpeg_set_dec_src(struct mtk_jpeg_ctx *ctx,
> +				 struct vb2_buffer *src_buf,
> +				 struct mtk_jpeg_bs *bs)
> +{
> +	bs->str_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
> +	bs->end_addr = bs->str_addr +
> +			 mtk_jpeg_align(vb2_get_plane_payload(src_buf, 0), 16);
> +	bs->size = mtk_jpeg_align(vb2_plane_size(src_buf, 0), 128);
> +}
> +
> +static int mtk_jpeg_set_dec_dst(struct mtk_jpeg_ctx *ctx,
> +				struct mtk_jpeg_dec_param *param,
> +				struct vb2_buffer *dst_buf,
> +				struct mtk_jpeg_fb *fb)
> +{
> +	int i;
> +
> +	if (param->comp_num != dst_buf->num_planes) {
> +		dev_err(ctx->jpeg->dev, "plane number mismatch (%u != %u)\n",
> +			param->comp_num, dst_buf->num_planes);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < dst_buf->num_planes; i++) {
> +		if (vb2_plane_size(dst_buf, i) < param->comp_size[i]) {
> +			dev_err(ctx->jpeg->dev,
> +				"buffer size is underflow (%lu < %u)\n",
> +				vb2_plane_size(dst_buf, 0),
> +				param->comp_size[i]);
> +			return -EINVAL;
> +		}
> +		fb->plane_addr[i] = vb2_dma_contig_plane_dma_addr(dst_buf, i);
> +	}
> +
> +	return 0;
> +}
> +
> +static void mtk_jpeg_device_run(void *priv)
> +{
> +	struct mtk_jpeg_ctx *ctx = priv;
> +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> +	struct vb2_buffer *src_buf, *dst_buf;
> +	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
> +	unsigned long flags;
> +	struct mtk_jpeg_src_buf *jpeg_src_buf;
> +	struct mtk_jpeg_bs bs;
> +	struct mtk_jpeg_fb fb;
> +	int i;
> +
> +	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
> +	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
> +	jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(src_buf);
> +
> +	if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) {
> +		for (i = 0; i < dst_buf->num_planes; i++)
> +			vb2_set_plane_payload(dst_buf, i, 0);
> +		buf_state = VB2_BUF_STATE_DONE;
> +		goto dec_end;
> +	}
> +
> +	if (mtk_jpeg_check_resolution_change(ctx, &jpeg_src_buf->dec_param)) {
> +		mtk_jpeg_queue_src_chg_event(ctx);
> +		ctx->state = MTK_JPEG_SOURCE_CHANGE;
> +		v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> +		return;
> +	}
> +
> +	mtk_jpeg_set_dec_src(ctx, src_buf, &bs);
> +	if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, dst_buf, &fb))
> +		goto dec_end;
> +
> +	spin_lock_irqsave(&jpeg->hw_lock, flags);
> +	mtk_jpeg_dec_reset(jpeg->dec_reg_base);
> +	mtk_jpeg_dec_set_config(jpeg->dec_reg_base,
> +				&jpeg_src_buf->dec_param, &bs, &fb);
> +
> +	mtk_jpeg_dec_start(jpeg->dec_reg_base);
> +	spin_unlock_irqrestore(&jpeg->hw_lock, flags);
> +	return;
> +
> +dec_end:
> +	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> +	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> +	v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), buf_state);
> +	v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), buf_state);
> +	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> +}
> +
> +static int mtk_jpeg_job_ready(void *priv)
> +{
> +	struct mtk_jpeg_ctx *ctx = priv;
> +
> +	return (ctx->state == MTK_JPEG_RUNNING) ? 1 : 0;
> +}
> +
> +static void mtk_jpeg_job_abort(void *priv)
> +{
> +	struct mtk_jpeg_ctx *ctx = priv;
> +	struct mtk_jpeg_dev *jpeg = ctx->jpeg;
> +	struct vb2_buffer *src_buf, *dst_buf;
> +
> +	src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> +	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> +	v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), VB2_BUF_STATE_ERROR);
> +	v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), VB2_BUF_STATE_ERROR);
> +	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> +}
> +
> +static struct v4l2_m2m_ops mtk_jpeg_m2m_ops = {
> +	.device_run = mtk_jpeg_device_run,
> +	.job_ready  = mtk_jpeg_job_ready,
> +	.job_abort  = mtk_jpeg_job_abort,
> +};
> +
> +static int mtk_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
> +			       struct vb2_queue *dst_vq)
> +{
> +	struct mtk_jpeg_ctx *ctx = priv;
> +	int ret;
> +
> +	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> +	src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;

I would drop USERPTR, it really makes little sense for dma_contig.

> +	src_vq->drv_priv = ctx;
> +	src_vq->buf_struct_size = sizeof(struct mtk_jpeg_src_buf);
> +	src_vq->ops = &mtk_jpeg_qops;
> +	src_vq->mem_ops = &vb2_dma_contig_memops;
> +	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> +	src_vq->lock = &ctx->jpeg->lock;
> +	src_vq->dev = ctx->jpeg->dev;
> +	ret = vb2_queue_init(src_vq);
> +	if (ret)
> +		return ret;
> +
> +	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> +	dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;

Ditto.

> +	dst_vq->drv_priv = ctx;
> +	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
> +	dst_vq->ops = &mtk_jpeg_qops;
> +	dst_vq->mem_ops = &vb2_dma_contig_memops;
> +	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> +	dst_vq->lock = &ctx->jpeg->lock;
> +	dst_vq->dev = ctx->jpeg->dev;
> +	ret = vb2_queue_init(dst_vq);
> +
> +	return ret;
> +}
> +
> +static void mtk_jpeg_clk_on(struct mtk_jpeg_dev *jpeg)
> +{
> +	int ret;
> +
> +	ret = mtk_smi_larb_get(jpeg->larb);
> +	if (ret)
> +		dev_err(jpeg->dev, "mtk_smi_larb_get larbvdec fail %d\n", ret);
> +	clk_prepare_enable(jpeg->clk_jdec_smi);
> +	clk_prepare_enable(jpeg->clk_jdec);
> +}
> +
> +static void mtk_jpeg_clk_off(struct mtk_jpeg_dev *jpeg)
> +{
> +	clk_disable_unprepare(jpeg->clk_jdec);
> +	clk_disable_unprepare(jpeg->clk_jdec_smi);
> +	mtk_smi_larb_put(jpeg->larb);
> +}
> +
> +static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv)
> +{
> +	struct mtk_jpeg_dev *jpeg = priv;
> +	struct mtk_jpeg_ctx *ctx;
> +	struct vb2_buffer *src_buf, *dst_buf;
> +	struct mtk_jpeg_src_buf *jpeg_src_buf;
> +	enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
> +	u32	dec_irq_ret;
> +	u32 dec_ret;
> +	int i;
> +
> +	ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
> +	if (!ctx) {
> +		v4l2_err(&jpeg->v4l2_dev, "Context is NULL\n");
> +		return IRQ_HANDLED;
> +	}
> +
> +	src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> +	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> +	jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(src_buf);
> +
> +	dec_ret = mtk_jpeg_dec_get_int_status(jpeg->dec_reg_base);
> +	dec_irq_ret = mtk_jpeg_dec_enum_result(dec_ret);
> +
> +	if (dec_irq_ret >= MTK_JPEG_DEC_RESULT_UNDERFLOW)
> +		mtk_jpeg_dec_reset(jpeg->dec_reg_base);
> +
> +	if (dec_irq_ret != MTK_JPEG_DEC_RESULT_EOF_DONE) {
> +		dev_err(jpeg->dev, "decode failed\n");
> +		goto dec_end;
> +	}
> +
> +	for (i = 0; i < dst_buf->num_planes; i++)
> +		vb2_set_plane_payload(dst_buf, i,
> +				      jpeg_src_buf->dec_param.comp_size[i]);
> +
> +	buf_state = VB2_BUF_STATE_DONE;
> +
> +dec_end:
> +	v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), buf_state);
> +	v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), buf_state);
> +	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
> +	return IRQ_HANDLED;
> +}
> +
> +static void mtk_jpeg_set_default_params(struct mtk_jpeg_ctx *ctx)
> +{
> +	struct mtk_jpeg_q_data *q = &ctx->out_q;
> +	int i;
> +
> +	ctx->colorspace = V4L2_COLORSPACE_JPEG,
> +	ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> +	ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
> +	ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
> +
> +	q->fmt = mtk_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
> +					      MTK_JPEG_FMT_TYPE_OUTPUT);
> +	q->w = MTK_JPEG_MIN_WIDTH;
> +	q->h = MTK_JPEG_MIN_HEIGHT;
> +	q->bytesperline[0] = 0;
> +	q->sizeimage[0] = MTK_JPEG_DEFAULT_SIZEIMAGE;
> +
> +	q = &ctx->cap_q;
> +	q->fmt = mtk_jpeg_find_format(ctx, V4L2_PIX_FMT_YUV420M,
> +					      MTK_JPEG_FMT_TYPE_CAPTURE);
> +	q->w = MTK_JPEG_MIN_WIDTH;
> +	q->h = MTK_JPEG_MIN_HEIGHT;
> +
> +	for (i = 0; i < q->fmt->colplanes; i++) {
> +		u32 stride = q->w * q->fmt->h_sample[i] / 4;
> +		u32 h = q->h * q->fmt->v_sample[i] / 4;
> +
> +		q->bytesperline[i] = stride;
> +		q->sizeimage[i] = stride * h;
> +	}
> +}
> +
> +static int mtk_jpeg_open(struct file *file)
> +{
> +	struct mtk_jpeg_dev *jpeg = video_drvdata(file);
> +	struct video_device *vfd = video_devdata(file);
> +	struct mtk_jpeg_ctx *ctx;
> +	int ret = 0;
> +
> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return -ENOMEM;
> +
> +	if (mutex_lock_interruptible(&jpeg->lock)) {
> +		ret = -ERESTARTSYS;
> +		goto free;
> +	}
> +
> +	v4l2_fh_init(&ctx->fh, vfd);
> +	file->private_data = &ctx->fh;
> +	v4l2_fh_add(&ctx->fh);
> +
> +	ctx->jpeg = jpeg;
> +	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx,
> +					    mtk_jpeg_queue_init);
> +	if (IS_ERR(ctx->fh.m2m_ctx)) {
> +		ret = PTR_ERR(ctx->fh.m2m_ctx);
> +		goto error;
> +	}
> +
> +	mtk_jpeg_set_default_params(ctx);
> +	mutex_unlock(&jpeg->lock);
> +	return 0;
> +
> +error:
> +	v4l2_fh_del(&ctx->fh);
> +	v4l2_fh_exit(&ctx->fh);
> +	mutex_unlock(&jpeg->lock);
> +free:
> +	kfree(ctx);
> +	return ret;
> +}
> +
> +static int mtk_jpeg_release(struct file *file)
> +{
> +	struct mtk_jpeg_dev *jpeg = video_drvdata(file);
> +	struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(file->private_data);
> +
> +	mutex_lock(&jpeg->lock);
> +	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
> +	v4l2_fh_del(&ctx->fh);
> +	v4l2_fh_exit(&ctx->fh);
> +	kfree(ctx);
> +	mutex_unlock(&jpeg->lock);
> +	return 0;
> +}
> +
> +static const struct v4l2_file_operations mtk_jpeg_fops = {
> +	.owner          = THIS_MODULE,
> +	.open           = mtk_jpeg_open,
> +	.release        = mtk_jpeg_release,
> +	.poll           = v4l2_m2m_fop_poll,
> +	.unlocked_ioctl = video_ioctl2,
> +	.mmap           = v4l2_m2m_fop_mmap,
> +};
> +
> +static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg)
> +{
> +	struct device_node *node;
> +	struct platform_device *pdev;
> +
> +	node = of_parse_phandle(jpeg->dev->of_node, "mediatek,larb", 0);
> +	if (!node)
> +		return -EINVAL;
> +	pdev = of_find_device_by_node(node);
> +	if (WARN_ON(!pdev)) {
> +		of_node_put(node);
> +		return -EINVAL;
> +	}
> +	of_node_put(node);
> +
> +	jpeg->larb = &pdev->dev;
> +
> +	jpeg->clk_jdec = devm_clk_get(jpeg->dev, "jpgdec");
> +	if (IS_ERR(jpeg->clk_jdec))
> +		return -EINVAL;
> +
> +	jpeg->clk_jdec_smi = devm_clk_get(jpeg->dev, "jpgdec-smi");
> +	if (IS_ERR(jpeg->clk_jdec_smi))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int mtk_jpeg_probe(struct platform_device *pdev)
> +{
> +	struct mtk_jpeg_dev *jpeg;
> +	struct resource *res;
> +	int dec_irq;
> +	int ret;
> +
> +	jpeg = devm_kzalloc(&pdev->dev, sizeof(*jpeg), GFP_KERNEL);
> +	if (!jpeg)
> +		return -ENOMEM;
> +
> +	mutex_init(&jpeg->lock);
> +	spin_lock_init(&jpeg->hw_lock);
> +	jpeg->dev = &pdev->dev;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	jpeg->dec_reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(jpeg->dec_reg_base)) {
> +		ret = PTR_ERR(jpeg->dec_reg_base);
> +		return ret;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +	dec_irq = platform_get_irq(pdev, 0);
> +	if (!res || dec_irq < 0) {
> +		dev_err(&pdev->dev, "Failed to get dec_irq %d.\n", dec_irq);
> +		ret = -EINVAL;
> +		return ret;
> +	}
> +
> +	ret = devm_request_irq(&pdev->dev, dec_irq, mtk_jpeg_dec_irq, 0,
> +			       pdev->name, jpeg);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to request dec_irq %d (%d)\n",
> +			dec_irq, ret);
> +		ret = -EINVAL;
> +		goto err_req_irq;
> +	}
> +
> +	ret = mtk_jpeg_clk_init(jpeg);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to init clk, err %d\n", ret);
> +		goto err_clk_init;
> +	}
> +
> +	ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to register v4l2 device\n");
> +		ret = -EINVAL;
> +		goto err_dev_register;
> +	}
> +
> +	jpeg->m2m_dev = v4l2_m2m_init(&mtk_jpeg_m2m_ops);
> +	if (IS_ERR(jpeg->m2m_dev)) {
> +		v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
> +		ret = PTR_ERR(jpeg->m2m_dev);
> +		goto err_m2m_init;
> +	}
> +
> +	jpeg->dec_vdev = video_device_alloc();
> +	if (!jpeg->dec_vdev) {
> +		ret = -ENOMEM;
> +		goto err_dec_vdev_alloc;
> +	}
> +	snprintf(jpeg->dec_vdev->name, sizeof(jpeg->dec_vdev->name),
> +		 "%s-dec", MTK_JPEG_NAME);
> +	jpeg->dec_vdev->fops = &mtk_jpeg_fops;
> +	jpeg->dec_vdev->ioctl_ops = &mtk_jpeg_ioctl_ops;
> +	jpeg->dec_vdev->minor = -1;
> +	jpeg->dec_vdev->release = video_device_release;
> +	jpeg->dec_vdev->lock = &jpeg->lock;
> +	jpeg->dec_vdev->v4l2_dev = &jpeg->v4l2_dev;
> +	jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M;
> +	jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING |
> +				      V4L2_CAP_VIDEO_M2M_MPLANE;
> +
> +	ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_GRABBER, 3);
> +	if (ret) {
> +		v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
> +		goto err_dec_vdev_register;
> +	}
> +
> +	video_set_drvdata(jpeg->dec_vdev, jpeg);
> +	v4l2_info(&jpeg->v4l2_dev,
> +		  "decoder device registered as /dev/video%d (%d,%d)\n",
> +		  jpeg->dec_vdev->num, VIDEO_MAJOR, jpeg->dec_vdev->minor);
> +
> +	platform_set_drvdata(pdev, jpeg);
> +
> +	pm_runtime_enable(&pdev->dev);
> +
> +	return 0;
> +
> +err_dec_vdev_register:
> +	video_device_release(jpeg->dec_vdev);
> +
> +err_dec_vdev_alloc:
> +	v4l2_m2m_release(jpeg->m2m_dev);
> +
> +err_m2m_init:
> +	v4l2_device_unregister(&jpeg->v4l2_dev);
> +
> +err_dev_register:
> +
> +err_clk_init:
> +
> +err_req_irq:
> +
> +	return ret;
> +}
> +
> +static int mtk_jpeg_remove(struct platform_device *pdev)
> +{
> +	struct mtk_jpeg_dev *jpeg = platform_get_drvdata(pdev);
> +
> +	pm_runtime_disable(&pdev->dev);
> +	video_unregister_device(jpeg->dec_vdev);
> +	video_device_release(jpeg->dec_vdev);
> +	v4l2_m2m_release(jpeg->m2m_dev);
> +	v4l2_device_unregister(&jpeg->v4l2_dev);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int mtk_jpeg_pm_suspend(struct device *dev)
> +{
> +	struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev);
> +
> +	mtk_jpeg_dec_reset(jpeg->dec_reg_base);
> +	mtk_jpeg_clk_off(jpeg);
> +
> +	return 0;
> +}
> +
> +static int mtk_jpeg_pm_resume(struct device *dev)
> +{
> +	struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev);
> +
> +	mtk_jpeg_clk_on(jpeg);
> +	mtk_jpeg_dec_reset(jpeg->dec_reg_base);
> +
> +	return 0;
> +}
> +#endif /* CONFIG_PM */
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int mtk_jpeg_suspend(struct device *dev)
> +{
> +	int ret;
> +
> +	if (pm_runtime_suspended(dev))
> +		return 0;
> +
> +	ret = mtk_jpeg_pm_suspend(dev);
> +	return ret;
> +}
> +
> +static int mtk_jpeg_resume(struct device *dev)
> +{
> +	int ret;
> +
> +	if (pm_runtime_suspended(dev))
> +		return 0;
> +
> +	ret = mtk_jpeg_pm_resume(dev);
> +
> +	return ret;
> +}
> +#endif /* CONFIG_PM_SLEEP */
> +
> +static const struct dev_pm_ops mtk_jpeg_pm_ops = {
> +	SET_SYSTEM_SLEEP_PM_OPS(mtk_jpeg_suspend, mtk_jpeg_resume)
> +	SET_RUNTIME_PM_OPS(mtk_jpeg_pm_suspend, mtk_jpeg_pm_resume, NULL)
> +};
> +
> +static const struct of_device_id mtk_jpeg_match[] = {
> +	{
> +		.compatible = "mediatek,mt8173-jpgdec",
> +		.data       = NULL,
> +	},
> +	{
> +		.compatible = "mediatek,mt2701-jpgdec",
> +		.data       = NULL,
> +	},
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, mtk_jpeg_match);
> +
> +static struct platform_driver mtk_jpeg_driver = {
> +	.probe = mtk_jpeg_probe,
> +	.remove = mtk_jpeg_remove,
> +	.driver = {
> +		.owner          = THIS_MODULE,
> +		.name           = MTK_JPEG_NAME,
> +		.of_match_table = mtk_jpeg_match,
> +		.pm             = &mtk_jpeg_pm_ops,
> +	},
> +};
> +
> +module_platform_driver(mtk_jpeg_driver);
> +
> +MODULE_DESCRIPTION("MediaTek JPEG codec driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h
> new file mode 100644
> index 0000000..d862e3b
> --- /dev/null
> +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h
> @@ -0,0 +1,141 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Ming Hsiu Tsai <minghsiu.tsai-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> + *         Rick Chang <rick.chang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef _MTK_JPEG_CORE_H
> +#define _MTK_JPEG_CORE_H
> +
> +#include <linux/interrupt.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-fh.h>
> +
> +#define MTK_JPEG_NAME		"mtk-jpeg"
> +
> +#define MTK_JPEG_FMT_FLAG_DEC_OUTPUT	BIT(0)
> +#define MTK_JPEG_FMT_FLAG_DEC_CAPTURE	BIT(1)
> +
> +#define MTK_JPEG_FMT_TYPE_OUTPUT	1
> +#define MTK_JPEG_FMT_TYPE_CAPTURE	2
> +
> +#define MTK_JPEG_MIN_WIDTH	32
> +#define MTK_JPEG_MIN_HEIGHT	32
> +#define MTK_JPEG_MAX_WIDTH	8192
> +#define MTK_JPEG_MAX_HEIGHT	8192
> +
> +#define MTK_JPEG_DEFAULT_SIZEIMAGE	(1 * 1024 * 1024)
> +
> +enum mtk_jpeg_ctx_state {
> +	MTK_JPEG_INIT = 0,
> +	MTK_JPEG_RUNNING,
> +	MTK_JPEG_SOURCE_CHANGE,
> +};
> +
> +/**
> + * struct mt_jpeg - JPEG IP abstraction
> + * @lock:		the mutex protecting this structure
> + * @hw_lock:		spinlock protecting the hw device resource
> + * @workqueue:		decode work queue
> + * @dev:		JPEG device
> + * @v4l2_dev:		v4l2 device for mem2mem mode
> + * @m2m_dev:		v4l2 mem2mem device data
> + * @alloc_ctx:		videobuf2 memory allocator's context
> + * @dec_vdev:		video device node for decoder mem2mem mode
> + * @dec_reg_base:	JPEG registers mapping
> + * @clk_jdec:		JPEG hw working clock
> + * @clk_jdec_smi:	JPEG SMI bus clock
> + * @larb:		SMI device
> + */
> +struct mtk_jpeg_dev {
> +	struct mutex		lock;
> +	spinlock_t		hw_lock;
> +	struct workqueue_struct	*workqueue;
> +	struct device		*dev;
> +	struct v4l2_device	v4l2_dev;
> +	struct v4l2_m2m_dev	*m2m_dev;
> +	void			*alloc_ctx;
> +	struct video_device	*dec_vdev;
> +	void __iomem		*dec_reg_base;
> +	struct clk		*clk_jdec;
> +	struct clk		*clk_jdec_smi;
> +	struct device		*larb;
> +};
> +
> +/**
> + * struct jpeg_fmt - driver's internal color format data
> + * @name:	format descritpion
> + * @fourcc:	the fourcc code, 0 if not applicable
> + * @h_sample:	horizontal sample count of plane in 4 * 4 pixel image
> + * @v_sample:	vertical sample count of plane in 4 * 4 pixel image
> + * @colplanes:	number of color planes (1 for packed formats)
> + * @h_align:	horizontal alignment order (align to 2^h_align)
> + * @v_align:	vertical alignment order (align to 2^v_align)
> + * @flags:	flags describing format applicability
> + */
> +struct mtk_jpeg_fmt {
> +	char	*name;
> +	u32	fourcc;
> +	int	h_sample[VIDEO_MAX_PLANES];
> +	int	v_sample[VIDEO_MAX_PLANES];
> +	int	colplanes;
> +	int	h_align;
> +	int	v_align;
> +	u32	flags;
> +};
> +
> +/**
> + * mtk_jpeg_q_data - parameters of one queue
> + * @fmt:	  driver-specific format of this queue
> + * @w:		  image width
> + * @h:		  image height
> + * @bytesperline: distance in bytes between the leftmost pixels in two adjacent
> + *                lines
> + * @sizeimage:	  image buffer size in bytes
> + */
> +struct mtk_jpeg_q_data {
> +	struct mtk_jpeg_fmt	*fmt;
> +	u32			w;
> +	u32			h;
> +	u32			bytesperline[VIDEO_MAX_PLANES];
> +	u32			sizeimage[VIDEO_MAX_PLANES];
> +};
> +
> +/**
> + * mtk_jpeg_ctx - the device context data
> + * @jpeg:		JPEG IP device for this context
> + * @out_q:		source (output) queue information
> + * @cap_q:		destination (capture) queue queue information
> + * @fh:			V4L2 file handle
> + * @dec_param		parameters for HW decoding
> + * @state:		state of the context
> + * @header_valid:	set if header has been parsed and valid
> + * @colorspace: enum v4l2_colorspace; supplemental to pixelformat
> + * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
> + * @quantization: enum v4l2_quantization, colorspace quantization
> + * @xfer_func: enum v4l2_xfer_func, colorspace transfer function
> + */
> +struct mtk_jpeg_ctx {
> +	struct mtk_jpeg_dev		*jpeg;
> +	struct mtk_jpeg_q_data		out_q;
> +	struct mtk_jpeg_q_data		cap_q;
> +	struct v4l2_fh			fh;
> +	enum mtk_jpeg_ctx_state		state;
> +
> +	enum v4l2_colorspace colorspace;
> +	enum v4l2_ycbcr_encoding ycbcr_enc;
> +	enum v4l2_quantization quantization;
> +	enum v4l2_xfer_func xfer_func;
> +};
> +
> +#endif /* _MTK_JPEG_CORE_H */
> diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c
> new file mode 100644
> index 0000000..a6315f3
> --- /dev/null
> +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c
> @@ -0,0 +1,417 @@
> +/*
> + * Copyright (c) 2016 MediaTek Inc.
> + * Author: Ming Hsiu Tsai <minghsiu.tsai-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> + *         Rick Chang <rick.chang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <media/videobuf2-core.h>
> +
> +#include "mtk_jpeg_hw.h"
> +
> +#define MTK_JPEG_DUNUM_MASK(val)	(((val) - 1) & 0x3)
> +
> +enum mtk_jpeg_color {
> +	MTK_JPEG_COLOR_420		= 0x00221111,
> +	MTK_JPEG_COLOR_422		= 0x00211111,
> +	MTK_JPEG_COLOR_444		= 0x00111111,
> +	MTK_JPEG_COLOR_422V		= 0x00121111,
> +	MTK_JPEG_COLOR_422X2		= 0x00412121,
> +	MTK_JPEG_COLOR_422VX2		= 0x00222121,
> +	MTK_JPEG_COLOR_400		= 0x00110000
> +};
> +
> +static inline int mtk_jpeg_verify_align(u32 val, int align, u32 reg)
> +{
> +	if (val & (align - 1)) {
> +		pr_err("mtk-jpeg: write reg %x without %d align\n", reg, align);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int mtk_jpeg_decide_format(struct mtk_jpeg_dec_param *param)
> +{
> +	param->src_color = (param->sampling_w[0] << 20) |
> +			   (param->sampling_h[0] << 16) |
> +			   (param->sampling_w[1] << 12) |
> +			   (param->sampling_h[1] << 8) |
> +			   (param->sampling_w[2] << 4) |
> +			   (param->sampling_h[2]);
> +
> +	param->uv_brz_w = 0;
> +	switch (param->src_color) {
> +	case MTK_JPEG_COLOR_444:
> +		param->uv_brz_w = 1;
> +		param->dst_fourcc = V4L2_PIX_FMT_YUV422M;
> +		break;
> +	case MTK_JPEG_COLOR_422X2:
> +	case MTK_JPEG_COLOR_422:
> +		param->dst_fourcc = V4L2_PIX_FMT_YUV422M;
> +		break;
> +	case MTK_JPEG_COLOR_422V:
> +	case MTK_JPEG_COLOR_422VX2:
> +		param->uv_brz_w = 1;
> +		param->dst_fourcc = V4L2_PIX_FMT_YUV420M;
> +		break;
> +	case MTK_JPEG_COLOR_420:
> +		param->dst_fourcc = V4L2_PIX_FMT_YUV420M;
> +		break;
> +	case MTK_JPEG_COLOR_400:
> +		param->dst_fourcc = V4L2_PIX_FMT_GREY;
> +		break;
> +	default:
> +		param->dst_fourcc = 0;
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static void mtk_jpeg_calc_mcu(struct mtk_jpeg_dec_param *param)
> +{
> +	u32 factor_w, factor_h;
> +	u32 i, comp, blk;
> +
> +	factor_w = 2 + param->sampling_w[0];
> +	factor_h = 2 + param->sampling_h[0];
> +	param->mcu_w = (param->pic_w + (1 << factor_w) - 1) >> factor_w;
> +	param->mcu_h = (param->pic_h + (1 << factor_h) - 1) >> factor_h;
> +	param->total_mcu = param->mcu_w * param->mcu_h;
> +	param->unit_num = ((param->pic_w + 7) >> 3) * ((param->pic_h + 7) >> 3);
> +	param->blk_num = 0;
> +	for (i = 0; i < MTK_JPEG_COMP_MAX; i++) {
> +		param->blk_comp[i] = 0;
> +		if (i >= param->comp_num)
> +			continue;
> +		param->blk_comp[i] = param->sampling_w[i] *
> +				     param->sampling_h[i];
> +		param->blk_num += param->blk_comp[i];
> +	}
> +
> +	param->membership = 0;
> +	for (i = 0, blk = 0, comp = 0; i < MTK_JPEG_BLOCK_MAX; i++) {
> +		if (i < param->blk_num && comp < param->comp_num) {
> +			u32 tmp;
> +
> +			tmp = (0x04 + (comp & 0x3));
> +			param->membership |= tmp << (i * 3);
> +			if (++blk == param->blk_comp[comp]) {
> +				comp++;
> +				blk = 0;
> +			}
> +		} else {
> +			param->membership |=  7 << (i * 3);
> +		}
> +	}
> +}
> +
> +static void mtk_jpeg_calc_dma_group(struct mtk_jpeg_dec_param *param)
> +{
> +	u32 factor_mcu = 3;
> +
> +	if (param->src_color == MTK_JPEG_COLOR_444 &&
> +	    param->dst_fourcc == V4L2_PIX_FMT_YUV422M)
> +		factor_mcu = 4;
> +	else if (param->src_color == MTK_JPEG_COLOR_422V &&
> +		 param->dst_fourcc == V4L2_PIX_FMT_YUV420M)
> +		factor_mcu = 4;
> +	else if (param->src_color == MTK_JPEG_COLOR_422X2 &&
> +		 param->dst_fourcc == V4L2_PIX_FMT_YUV422M)
> +		factor_mcu = 2;
> +	else if (param->src_color == MTK_JPEG_COLOR_400 ||
> +		 (param->src_color & 0x0FFFF) == 0)
> +		factor_mcu = 4;
> +
> +	param->dma_mcu = 1 << factor_mcu;
> +	param->dma_group = param->mcu_w / param->dma_mcu;
> +	param->dma_last_mcu = param->mcu_w % param->dma_mcu;
> +	if (param->dma_last_mcu)
> +		param->dma_group++;
> +	else
> +		param->dma_last_mcu = param->dma_mcu;
> +}
> +
> +static int mtk_jpeg_calc_dst_size(struct mtk_jpeg_dec_param *param)
> +{
> +	u32 i, padding_w;
> +	u32 ds_row_h[3];
> +	u32 brz_w[3];
> +
> +	brz_w[0] = 0;
> +	brz_w[1] = param->uv_brz_w;
> +	brz_w[2] = brz_w[1];
> +
> +	for (i = 0; i < param->comp_num; i++) {
> +		if (brz_w[i] > 3)
> +			return -1;
> +
> +		padding_w = param->mcu_w * MTK_JPEG_DCTSIZE *
> +				param->sampling_w[i];
> +		/* output format is 420/422 */
> +		param->comp_w[i] = padding_w >> brz_w[i];
> +		param->comp_w[i] = mtk_jpeg_align(param->comp_w[i],
> +						  MTK_JPEG_DCTSIZE);
> +		param->img_stride[i] = i ? mtk_jpeg_align(param->comp_w[i], 16)
> +					: mtk_jpeg_align(param->comp_w[i], 32);
> +		ds_row_h[i] = (MTK_JPEG_DCTSIZE * param->sampling_h[i]);
> +	}
> +	param->dec_w = param->img_stride[0];
> +	param->dec_h = ds_row_h[0] * param->mcu_h;
> +
> +	for (i = 0; i < MTK_JPEG_COMP_MAX; i++) {
> +		/* They must be equal in frame mode. */
> +		param->mem_stride[i] = param->img_stride[i];
> +		param->comp_size[i] = param->mem_stride[i] * ds_row_h[i] *
> +				      param->mcu_h;
> +	}
> +
> +	param->y_size = param->comp_size[0];
> +	param->uv_size = param->comp_size[1];
> +	param->dec_size = param->y_size + (param->uv_size << 1);
> +
> +	return 0;
> +}
> +
> +int mtk_jpeg_dec_fill_param(struct mtk_jpeg_dec_param *param)
> +{
> +	if (mtk_jpeg_decide_format(param))
> +		return -1;
> +
> +	mtk_jpeg_calc_mcu(param);
> +	mtk_jpeg_calc_dma_group(param);
> +	if (mtk_jpeg_calc_dst_size(param))
> +		return -2;
> +
> +	return 0;
> +}
> +
> +u32 mtk_jpeg_dec_get_int_status(void __iomem *base)
> +{
> +	u32 ret;
> +
> +	ret = readl(base + JPGDEC_REG_INTERRUPT_STATUS) & BIT_INQST_MASK_ALLIRQ;
> +	if (ret)
> +		writel(ret, base + JPGDEC_REG_INTERRUPT_STATUS);
> +
> +	return ret;
> +}
> +
> +u32 mtk_jpeg_dec_enum_result(u32 irq_result)
> +{
> +	if (irq_result & BIT_INQST_MASK_EOF)
> +		return MTK_JPEG_DEC_RESULT_EOF_DONE;
> +	else if (irq_result & BIT_INQST_MASK_PAUSE)
> +		return MTK_JPEG_DEC_RESULT_PAUSE;
> +	else if (irq_result & BIT_INQST_MASK_UNDERFLOW)
> +		return MTK_JPEG_DEC_RESULT_UNDERFLOW;
> +	else if (irq_result & BIT_INQST_MASK_OVERFLOW)
> +		return MTK_JPEG_DEC_RESULT_OVERFLOW;
> +	else if (irq_result & BIT_INQST_MASK_ERROR_BS)
> +		return MTK_JPEG_DEC_RESULT_ERROR_BS;

No need for 'else' here since the previous 'if' always returns if true.

> +
> +	return MTK_JPEG_DEC_RESULT_ERROR_UNKNOWN;
> +}
> +
> +void mtk_jpeg_dec_start(void __iomem *base)
> +{
> +	writel(0, base + JPGDEC_REG_TRIG);
> +}
> +
> +static void mtk_jpeg_dec_soft_reset(void __iomem *base)
> +{
> +	writel(0x0000FFFF, base + JPGDEC_REG_INTERRUPT_STATUS);
> +	writel(0x00, base + JPGDEC_REG_RESET);
> +	writel(0x01, base + JPGDEC_REG_RESET);
> +}
> +
> +static void mtk_jpeg_dec_hard_reset(void __iomem *base)
> +{
> +	writel(0x00, base + JPGDEC_REG_RESET);
> +	writel(0x10, base + JPGDEC_REG_RESET);
> +}
> +
> +void mtk_jpeg_dec_reset(void __iomem *base)
> +{
> +	mtk_jpeg_dec_soft_reset(base);
> +	mtk_jpeg_dec_hard_reset(base);
> +}
> +
> +static void mtk_jpeg_dec_set_brz_factor(void __iomem *base, u8 yscale_w,
> +					u8 yscale_h, u8 uvscale_w, u8 uvscale_h)
> +{
> +	u32 val;
> +
> +	val = (uvscale_h << 12) | (uvscale_w << 8) |
> +	      (yscale_h << 4) | yscale_w;
> +	writel(val, base + JPGDEC_REG_BRZ_FACTOR);
> +}
> +
> +static void mtk_jpeg_dec_set_dst_bank0(void __iomem *base, u32 addr_y,
> +				       u32 addr_u, u32 addr_v)
> +{
> +	mtk_jpeg_verify_align(addr_y, 16, JPGDEC_REG_DEST_ADDR0_Y);
> +	writel(addr_y, base + JPGDEC_REG_DEST_ADDR0_Y);
> +	mtk_jpeg_verify_align(addr_u, 16, JPGDEC_REG_DEST_ADDR0_U);
> +	writel(addr_u, base + JPGDEC_REG_DEST_ADDR0_U);
> +	mtk_jpeg_verify_align(addr_v, 16, JPGDEC_REG_DEST_ADDR0_V);
> +	writel(addr_v, base + JPGDEC_REG_DEST_ADDR0_V);
> +}
> +
> +static void mtk_jpeg_dec_set_dst_bank1(void __iomem *base, u32 addr_y,
> +				       u32 addr_u, u32 addr_v)
> +{
> +	writel(addr_y, base + JPGDEC_REG_DEST_ADDR1_Y);
> +	writel(addr_u, base + JPGDEC_REG_DEST_ADDR1_U);
> +	writel(addr_v, base + JPGDEC_REG_DEST_ADDR1_V);
> +}
> +
> +static void mtk_jpeg_dec_set_mem_stride(void __iomem *base, u32 stride_y,
> +					u32 stride_uv)
> +{
> +	writel((stride_y & 0xFFFF), base + JPGDEC_REG_STRIDE_Y);
> +	writel((stride_uv & 0xFFFF), base + JPGDEC_REG_STRIDE_UV);
> +}
> +
> +static void mtk_jpeg_dec_set_img_stride(void __iomem *base, u32 stride_y,
> +					u32 stride_uv)
> +{
> +	writel((stride_y & 0xFFFF), base + JPGDEC_REG_IMG_STRIDE_Y);
> +	writel((stride_uv & 0xFFFF), base + JPGDEC_REG_IMG_STRIDE_UV);
> +}
> +
> +static void mtk_jpeg_dec_set_pause_mcu_idx(void __iomem *base, u32 idx)
> +{
> +	writel(idx & 0x0003FFFFFF, base + JPGDEC_REG_PAUSE_MCU_NUM);
> +}
> +
> +static void mtk_jpeg_dec_set_dec_mode(void __iomem *base, u32 mode)
> +{
> +	writel(mode & 0x03, base + JPGDEC_REG_OPERATION_MODE);
> +}
> +
> +static void mtk_jpeg_dec_set_bs_write_ptr(void __iomem *base, u32 ptr)
> +{
> +	mtk_jpeg_verify_align(ptr, 16, JPGDEC_REG_FILE_BRP);
> +	writel(ptr, base + JPGDEC_REG_FILE_BRP);
> +}
> +
> +static void mtk_jpeg_dec_set_bs_info(void __iomem *base, u32 addr, u32 size)
> +{
> +	mtk_jpeg_verify_align(addr, 16, JPGDEC_REG_FILE_ADDR);
> +	mtk_jpeg_verify_align(size, 128, JPGDEC_REG_FILE_TOTAL_SIZE);
> +	writel(addr, base + JPGDEC_REG_FILE_ADDR);
> +	writel(size, base + JPGDEC_REG_FILE_TOTAL_SIZE);
> +}
> +
> +static void mtk_jpeg_dec_set_comp_id(void __iomem *base, u32 id_y, u32 id_u,
> +				     u32 id_v)
> +{
> +	u32 val;
> +
> +	val = ((id_y & 0x00FF) << 24) | ((id_u & 0x00FF) << 16) |
> +	      ((id_v & 0x00FF) << 8);
> +	writel(val, base + JPGDEC_REG_COMP_ID);
> +}
> +
> +static void mtk_jpeg_dec_set_total_mcu(void __iomem *base, u32 num)
> +{
> +	writel(num - 1, base + JPGDEC_REG_TOTAL_MCU_NUM);
> +}
> +
> +static void mtk_jpeg_dec_set_comp0_du(void __iomem *base, u32 num)
> +{
> +	writel(num - 1, base + JPGDEC_REG_COMP0_DATA_UNIT_NUM);
> +}
> +
> +static void mtk_jpeg_dec_set_du_membership(void __iomem *base, u32 member,
> +					   u32 gmc, u32 isgray)
> +{
> +	if (isgray)
> +		member = 0x3FFFFFFC;
> +	member |= (isgray << 31) | (gmc << 30);
> +	writel(member, base + JPGDEC_REG_DU_CTRL);
> +}
> +
> +static void mtk_jpeg_dec_set_q_table(void __iomem *base, u32 id0, u32 id1,
> +				     u32 id2)
> +{
> +	u32 val;
> +
> +	val = ((id0 & 0x0f) << 8) | ((id1 & 0x0f) << 4) | ((id2 & 0x0f) << 0);
> +	writel(val, base + JPGDEC_REG_QT_ID);
> +}
> +
> +static void mtk_jpeg_dec_set_dma_group(void __iomem *base, u32 mcu_group,
> +				       u32 group_num, u32 last_mcu)
> +{
> +	u32 val;
> +
> +	val = (((mcu_group - 1) & 0x00FF) << 16) |
> +	      (((group_num - 1) & 0x007F) << 8) |
> +	      ((last_mcu - 1) & 0x00FF);
> +	writel(val, base + JPGDEC_REG_WDMA_CTRL);
> +}
> +
> +static void mtk_jpeg_dec_set_sampling_factor(void __iomem *base, u32 comp_num,
> +					     u32 y_w, u32 y_h, u32 u_w,
> +					     u32 u_h, u32 v_w, u32 v_h)
> +{
> +	u32 val;
> +	u32 y_wh = (MTK_JPEG_DUNUM_MASK(y_w) << 2) | MTK_JPEG_DUNUM_MASK(y_h);
> +	u32 u_wh = (MTK_JPEG_DUNUM_MASK(u_w) << 2) | MTK_JPEG_DUNUM_MASK(u_h);
> +	u32 v_wh = (MTK_JPEG_DUNUM_MASK(v_w) << 2) | MTK_JPEG_DUNUM_MASK(v_h);
> +
> +	if (comp_num == 1)
> +		val = 0;
> +	else
> +		val = (y_wh << 8) | (u_wh << 4) | v_wh;
> +	writel(val, base + JPGDEC_REG_DU_NUM);
> +}
> +
> +void mtk_jpeg_dec_set_config(void __iomem *base,
> +			     struct mtk_jpeg_dec_param *config,
> +			     struct mtk_jpeg_bs *bs,
> +			     struct mtk_jpeg_fb *fb)
> +{
> +	mtk_jpeg_dec_set_brz_factor(base, 0, 0, config->uv_brz_w, 0);
> +	mtk_jpeg_dec_set_dec_mode(base, 0);
> +	mtk_jpeg_dec_set_comp0_du(base, config->unit_num);
> +	mtk_jpeg_dec_set_total_mcu(base, config->total_mcu);
> +	mtk_jpeg_dec_set_bs_info(base, bs->str_addr, bs->size);
> +	mtk_jpeg_dec_set_bs_write_ptr(base, bs->end_addr);
> +	mtk_jpeg_dec_set_du_membership(base, config->membership, 1,
> +				       (config->comp_num == 1) ? 1 : 0);
> +	mtk_jpeg_dec_set_comp_id(base, config->comp_id[0], config->comp_id[1],
> +				 config->comp_id[2]);
> +	mtk_jpeg_dec_set_q_table(base, config->qtbl_num[0],
> +				 config->qtbl_num[1], config->qtbl_num[2]);
> +	mtk_jpeg_dec_set_sampling_factor(base, config->comp_num,
> +					 config->sampling_w[0],
> +					 config->sampling_h[0],
> +					 config->sampling_w[1],
> +					 config->sampling_h[1],
> +					 config->sampling_w[2],
> +					 config->sampling_h[2]);
> +	mtk_jpeg_dec_set_mem_stride(base, config->mem_stride[0],
> +				    config->mem_stride[1]);
> +	mtk_jpeg_dec_set_img_stride(base, config->img_stride[0],
> +				    config->img_stride[1]);
> +	mtk_jpeg_dec_set_dst_bank0(base, fb->plane_addr[0],
> +				   fb->plane_addr[1], fb->plane_addr[2]);
> +	mtk_jpeg_dec_set_dst_bank1(base, 0, 0, 0);
> +	mtk_jpeg_dec_set_dma_group(base, config->dma_mcu, config->dma_group,
> +				   config->dma_last_mcu);
> +	mtk_jpeg_dec_set_pause_mcu_idx(base, config->total_mcu);
> +}

Regards,

	Hans
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH V5 3/3] ARM64 LPC: LPC driver implementation on Hip06
From: liviu.dudau-5wv7dgnIgG8 @ 2016-11-11 14:45 UTC (permalink / raw)
  To: Gabriele Paoloni
  Cc: Arnd Bergmann,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	Yuanzhichang, mark.rutland-5wv7dgnIgG8@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org,
	minyard-HInyCGIudOg@public.gmane.org,
	linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org,
	John Garry, will.deacon-5wv7dgnIgG8@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, xuwei (O),
	Linuxarm, zourongrong-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org
In-Reply-To: <EE11001F9E5DDD47B7634E2F8A612F2E1F8F900A@lhreml507-mbx>

On Fri, Nov 11, 2016 at 01:39:35PM +0000, Gabriele Paoloni wrote:
> Hi Arnd
> 
> > -----Original Message-----
> > From: Arnd Bergmann [mailto:arnd-r2nGTMty4D4@public.gmane.org]
> > Sent: 10 November 2016 16:07
> > To: Gabriele Paoloni
> > Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org; Yuanzhichang;
> > mark.rutland-5wv7dgnIgG8@public.gmane.org; devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org;
> > lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org; minyard-HInyCGIudOg@public.gmane.org; linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org;
> > benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org; John Garry; will.deacon-5wv7dgnIgG8@public.gmane.org; linux-
> > kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; xuwei (O); Linuxarm; zourongrong-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org;
> > robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org; kantyzc-9Onoh4P/yGk@public.gmane.org; linux-serial-u79uwXL29TY76Z2rM5mHXA@public.gmane.org;
> > catalin.marinas-5wv7dgnIgG8@public.gmane.org; olof-nZhT3qVonbNeoWH0uzbU5w@public.gmane.org; liviu.dudau-5wv7dgnIgG8@public.gmane.org;
> > bhelgaas@googl e.com; zhichang.yuan02-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
> > Subject: Re: [PATCH V5 3/3] ARM64 LPC: LPC driver implementation on
> > Hip06
> > 
> > On Thursday, November 10, 2016 3:36:49 PM CET Gabriele Paoloni wrote:
> > >
> > > Where should we get the range from? For LPC we know that it is going
> > > Work on anything that is not used by PCI I/O space, and this is
> > > why we use [0, PCIBIOS_MIN_IO]
> > 
> > It should be allocated the same way we allocate PCI config space
> > segments. This is currently done with the io_range list in
> > drivers/pci/pci.c, which isn't perfect but could be extended
> > if necessary. Based on what others commented here, I'd rather
> > make the differences between ISA/LPC and PCI I/O ranges smaller
> > than larger.

Gabriele,

> 
> I am not sure this would make sense...
> 
> IMHO all the mechanism around io_range_list is needed to provide the
> "mapping" between I/O tokens and physical CPU addresses.
> 
> Currently the available tokens range from 0 to IO_SPACE_LIMIT.
> 
> As you know the I/O memory accessors operate on whatever
> __of_address_to_resource sets into the resource (start, end).
> 
> With this special device in place we cannot know if a resource is
> assigned with an I/O token or a physical address, unless we forbid
> the I/O tokens to be in a specific range.
> 
> So this is why we are changing the offsets of all the functions
> handling io_range_list (to make sure that a range is forbidden to
> the tokens and is available to the physical addresses).
> 
> We have chosen this forbidden range to be [0, PCIBIOS_MIN_IO)
> because this is the maximum physical I/O range that a non PCI device
> can operate on and because we believe this does not impose much
> restriction on the available I/O token range; that now is 
> [PCIBIOS_MIN_IO, IO_SPACE_LIMIT].
> So we believe that the chosen forbidden range can accommodate
> any special ISA bus device with no much constraint on the rest
> of I/O tokens...

Your idea is a good one, however you are abusing PCIBIOS_MIN_IO and you
actually need another variable for "reserving" an area in the I/O space
that can be used for physical addresses rather than I/O tokens.

The one good example for using PCIBIOS_MIN_IO is when your platform/architecture
does not support legacy ISA operations *at all*. In that case someone
sets the PCIBIOS_MIN_IO to a non-zero value to reserve that I/O range
so that it doesn't get used. With Zhichang's patch you now start forcing
those platforms to have a valid address below PCIBIOS_MIN_IO.

For the general case you also have to bear in mind that PCIBIOS_MIN_IO could
be zero. In that case, what is your "forbidden" range? [0, 0) ? So it makes
sense to add a new #define that should only be defined by those architectures/
platforms that want to reserve on top of PCIBIOS_MIN_IO another region
where I/O tokens can't be generated for.

Best regards,
Liviu

> 
> > 
> > > > Your current version has
> > > >
> > > >         if (arm64_extio_ops->pfout)                             \
> > > >                 arm64_extio_ops->pfout(arm64_extio_ops->devpara,\
> > > >                        addr, value, sizeof(type));             \
> > > >
> > > > Instead, just subtract the start of the range from the logical
> > > > port number to transform it back into a bus-local port number:
> > >
> > > These accessors do not operate on IO tokens:
> > >
> > > If (arm64_extio_ops->start > addr || arm64_extio_ops->end < addr)
> > > addr is not going to be an I/O token; in fact patch 2/3 imposes that
> > > the I/O tokens will start at PCIBIOS_MIN_IO. So from 0 to
> > PCIBIOS_MIN_IO
> > > we have free physical addresses that the accessors can operate on.
> > 
> > Ah, I missed that part. I'd rather not use PCIBIOS_MIN_IO to refer to
> > the logical I/O tokens, the purpose of that macro is really meant
> > for allocating PCI I/O port numbers within the address space of
> > one bus.
> 
> As I mentioned above, special devices operate on CPU addresses directly,
> not I/O tokens. For them there is no way to distinguish....
> 
> > 
> > Note that it's equally likely that whichever next platform needs
> > non-mapped I/O access like this actually needs them for PCI I/O space,
> > and that will use it on addresses registered to a PCI host bridge.
> 
> Ok so here you are talking about a platform that has got an I/O range
> under the PCI host controller, right?
> And this I/O range cannot be directly memory mapped but needs special
> redirections for the I/O tokens, right?
> 
> In this scenario registering the I/O ranges with the forbidden range
> implemented by the current patch would still allow to redirect I/O
> tokens as long as arm64_extio_ops->start >= PCIBIOS_MIN_IO
> 
> So effectively the special PCI host controller
> 1) knows the physical range that needs special redirection
> 2) register such range
> 3) uses pci_pio_to_address() to retrieve the IO tokens for the
>    special accessors
> 4) sets arm64_extio_ops->start/end to the IO tokens retrieved in 3)
> 
> So to be honest I think this patch can fit well both with
> special PCI controllers that need I/O tokens redirection and with
> special non-PCI controllers that need non-PCI I/O physical
> address redirection...
> 
> Thanks (and sorry for the long reply but I didn't know how
> to make the explanation shorter :) )
> 
> Gab
> 
> > 
> > If we separate the two steps:
> > 
> > a) assign a range of logical I/O port numbers to a bus
> > b) register a set of helpers for redirecting logical I/O
> >    port to a helper function
> > 
> > then I think the code will get cleaner and more flexible.
> > It should actually then be able to replace the powerpc
> > specific implementation.
> > 
> > 	Arnd

-- 
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v5 6/8] Documentation: bindings: add compatible specific to legacy SCPI protocol
From: Sudeep Holla @ 2016-11-11 14:19 UTC (permalink / raw)
  To: Rob Herring
  Cc: Sudeep Holla, Olof Johansson, Neil Armstrong,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <CAL_JsqJ5PxzM_VMP55m+6snkqyWSMSsdCOiUzYWkMTb3LkD5Mw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>



On 11/11/16 13:34, Rob Herring wrote:
> On Fri, Nov 11, 2016 at 1:48 AM, Sudeep Holla <sudeep.holla-5wv7dgnIgG8@public.gmane.org> wrote:
>> On 10/11/16 19:03, Olof Johansson wrote:
>>> On Thu, Nov 10, 2016 at 6:34 AM, Sudeep Holla <sudeep.holla-5wv7dgnIgG8@public.gmane.org>
>>> wrote:
>
> [...]
>
>>>> E.g. Amlogic follows most of the legacy protocol though it deviates in
>>>> couple of things which we can handle with platform specific compatible
>>>> (in the following patch in the series). When another user(Rockchip ?)
>>>> make use of this legacy protocol, we can start using those platform
>>>> specific compatible for deviations only.
>>>>
>>>> Is that not acceptable ?
>>>
>>>
>>> If there's no shared legacy feature set, then it's probably less
>>> useful to have a shared less precise compatible value.
>>>
>>
>> There is and will be some shared feature set for sure. At the least the
>> standard command set will be shared.
>>
>>> What the main point I was trying to get across was that we shouldn't
>>> expand the generic binding with per-vendor compatible fields, instead
>>> we should have those as extensions on the side.
>>>
>>
>> Yes I get the point. We will have per-vendor compatibles for handle the
>> deviations but generic one to handle the shared set.
>>
>>> I'm also a little apprehensive of using "legacy", it goes in the same
>>> bucket as "misc". At some point 1.0 will be legacy too, etc.
>>>
>>
>> True and I agree, how about "arm,scpi-pre-1.0" instead ?
>
> That's still meaningless. Convince me that multiple implementations
> are identical, then we can have a common property. For example, how
> many releases did ARM make before 1.0.
>

None officially, so I tend to agree with you on this.

But so far we have seen some commonality between Rockchip and Amlogic
implementations, which in fact shares some commonality with early
release of SCPI from ARM (there are based on the same SCP code base,
which is closed source and released to partners only). ARM improved the
specification and the code base before the official release but by then
it was adopted(as usual we were late ;))

IMO, it's might be useful to have more generic say "arm,scpi-pre-1.0"
and platform specific "amlogic,meson-gxbb-scpi"

-- 
Regards,
Sudeep
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [RFC 5/5] doc_rst: media: New SDR formats SC16, SC18 & SC20
From: Hans Verkuil @ 2016-11-11 14:00 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Ramesh Shanmugasundaram, Antti Palosaari, robh+dt@kernel.org,
	mark.rutland@arm.com, mchehab@kernel.org,
	sakari.ailus@linux.intel.com, Chris Paterson,
	geert@linux-m68k.org, linux-media@vger.kernel.org,
	devicetree@vger.kernel.org, linux-renesas-soc@vger.kernel.org
In-Reply-To: <1980094.XQVzRRgZQ8@avalon>

On 11/11/2016 02:57 PM, Laurent Pinchart wrote:
> Hi Hans,
> 
> On Friday 11 Nov 2016 14:53:58 Hans Verkuil wrote:
>> On 11/10/2016 09:08 AM, Laurent Pinchart wrote:
>>> Antti, Hans, ping ? Please see below.
>>>
>>> On Friday 04 Nov 2016 09:23:29 Ramesh Shanmugasundaram wrote:
>>>>> On 11/02/2016 10:58 PM, Laurent Pinchart wrote:
>>>>>> On Wednesday 02 Nov 2016 09:00:00 Ramesh Shanmugasundaram wrote:
>>>>>>>>> On Wednesday 12 Oct 2016 15:10:29 Ramesh Shanmugasundaram wrote:
>>>>>>>>>> This patch adds documentation for the three new SDR formats
>>>>>>>>>>
>>>>>>>>>> V4L2_SDR_FMT_SCU16BE
>>>>>>>>>> V4L2_SDR_FMT_SCU18BE
>>>>>>>>>> V4L2_SDR_FMT_SCU20BE
>>>>>>>
>>>>>>> [snip]
>>>>>>>
>>>>>>>>>> +
>>>>>>>>>> +       -  start + 0:
>>>>>>>>>> +
>>>>>>>>>> +       -  I'\ :sub:`0[D13:D6]`
>>>>>>>>>> +
>>>>>>>>>> +       -  I'\ :sub:`0[D5:D0]`
>>>>>>>>>> +
>>>>>>>>>> +    -  .. row 2
>>>>>>>>>> +
>>>>>>>>>> +       -  start + buffer_size/2:
>>>>>>>>>> +
>>>>>>>>>> +       -  Q'\ :sub:`0[D13:D6]`
>>>>>>>>>> +
>>>>>>>>>> +       -  Q'\ :sub:`0[D5:D0]`
>>>>>>>>>
>>>>>>>>> The format looks planar, does it use one V4L2 plane (as does NV12)
>>>>>>>>> or two V4L2 planes (as does NV12M) ? Same question for the other
>>>>>>>>> formats.
>>>>>>>>
>>>>>>>> Thank you for bringing up this topic. This is one of the key design
>>>>>>>> dilemma.
>>>>>>>>
>>>>>>>> The I & Q data for these three SDR formats comes from two different
>>>>>>>> DMA channels and hence two separate pointers -> we could say it is
>>>>>>>> v4l2 multi- planar. Right now, I am making it look like a single
>>>>>>>> plane by presenting the data in one single buffer ptr.
>>>>>>>>
>>>>>>>> For e.g. multi-planar SC16 format would look something like this
>>>>>>>>
>>>>>>>> <------------------------32bits---------------------->
>>>>>>>> <--I(14 bit data) + 2bit status--16bit padded zeros--> : start0 + 0
>>>>>>>> <--I(14 bit data) + 2bit status--16bit padded zeros--> : start0 + 4
>>>>>>>> ...
>>>>>>>> <--Q(14 bit data) + 2bit status--16bit padded zeros--> : start1 + 0
>>>>>>>> <--Q(14 bit data) + 2bit status--16bit padded zeros--> : start1 + 4
>>>>>>>>
>>>>>>>> My concerns are
>>>>>>>>
>>>>>>>> 1) These formats are not a standard as the video "Image Formats".
>>>>>>>> These formats are possible when we use DRIF + MAX2175 combination.
>>>>>>>> If we interface with a different tuner vendor, the above format(s)
>>>>>>>> MAY/MAY NOT be re-usable. We do not know at this point. This is the
>>>>>>>> main open item for discussion in the cover letter.
>>>>>>
>>>>>> If the formats are really device-specific then they should be
>>>>>> documented accordingly and not made generic.
>>>>>>
>>>>>>>> 2) MPLANE support within V4L2 seems specific to video. Please
>>>>>>>> correct me if this is wrong interpretation.
>>>>>>>>
>>>>>>>> - struct v4l2_format contains v4l2_sdr_format and
>>>>>>>> v4l2_pix_format_mplane as members of union. Should I create a new
>>>>>>>> v4l2_sdr_format_mplane? If I have to use v4l2_pix_format_mplane most
>>>>>>>> of the video specific members would be unused (it would be similar
>>>>>>>> to using v4l2_pix_format itself instead of v4l2_sdr_format)?
>>>>>>
>>>>>> I have no answer to that question as I'm not familiar with SDR. Antti,
>>>>>> you've added v4l2_sdr_format to the API, what's your opinion ? Hans,
>>>>>> as you've acked the patch, your input would be appreciated as well.
>>>>>
>>>>> If I understood correctly this hardware provides I and Q samples via
>>>>> different channels and driver now combines those channels as a
>>>>> sequential
>>>>> IQ sample pairs.
>>>>
>>>> The driver combines the two buffer ptrs and present as one single buffer.
>>>> For a buffer of size 200
>>>>
>>>> ptr + 0   : I I I I ... I
>>>> ptr + 100 : Q Q Q Q ... Q
>>>>
>>>>> I have never seen any other than hw which provides IQ IQ IQ IQ ... IQ.
>>>>
>>>> There are some modes where this h/w combo can also do IQ IQ IQ pattern.
>>>> Those modes are not added in the RFC patchset.
>>>>
>>>>> This is
>>>>> I I I I ... I
>>>>> Q Q Q Q ... Q
>>>>> I am not very familiar with planars, but it sounds like it is correct
>>>>> approach. So I think should be added rather than emulate packet
>>>>> sequential format.
>>>>
>>>> My understanding of V4L2 MPLANE constructs is limited to a quick code
>>>> read
>>>> only. At this point MPLANE support seems specific to video. SDR is
>>>> defined
>>>> as separate format like v4l2_pix_format. Questions would be - should we
>>>> define new SDR_MPLANE? or merge SDR format with pix format & reuse
>>>> existing
>>>> MPLANE with some SDR extensions (if possible)? These seem big design
>>>> decisions. Any suggestions please?
>>>>
>>>> For my use case, MPLANE support does not seem to add significant benefit
>>>> except it may be syntactically correct. I am doing cyclic DMA with a
>>>> small
>>>> set of h/w buffers and copying each stage to one mmapped vmalloc
>>>> vb2_buffer
>>>> at two offsets. If we add MPLANE support, it can be two non-contiguous
>>>> buffer pointers.
>>>>
>>>>>>>> - The above decision (accomodate SDR & MPLANE) needs to be
>>>>>>>> propagated across the framework. Is this the preferred approach?
>>>>>>>>
>>>>>>>> It goes back to point (1). As of today, the change set for this
>>>>>>>> combo (DRIF+MAX2175) introduces new SDR formats only. Should it add
>>>>>>>> further SDR+MPLANE support to the framework as well?
>>>>>>>>
>>>>>>>> I would appreciate your suggestions on this regard.
>>
>> Some terminology first:
>>
>> Planar formats separate the data into different memory areas: in this case
>> one part is all I and one part is all Q. This as opposed to interleaved
>> formats (IQIQIQIQ....).
>>
>> As long as both planes fit in the same buffer all is fine. Since that is
>> the case here there is no need to introduce a new MPLANE API.
>>
>> The MPLANE API was added for video to handle cases where the two planes
>> had to be in two different non-contiguous buffers.
> 
> Not only that, it can also be used for cases where storing the two planes in 
> separate buffers can be beneficial, even if a single contiguous buffer could 
> work.
> 
>> So instead of passing one buffer pointer, you need to pass two or more
>> buffer pointers.
>>
>> In hindsight we should have called it the MBUFFER API.
> 
> The name was badly chosen, yes.
> 
>> Oh well...
>>
>> Anyway, since there is no problem here apparently to keep both planes
>> in one buffer there is also no need to introduce a SDR_MPLANE.
> 
> The question here is whether there could be a benefit in separating I and Q 
> data in two buffers compared to storing them in the same buffer.
> 

The MPLANE API is very messy and introducing something like SDR_MPLANE is not
something I would promote. If we want that, then we should first make a new
v4l2_buffer struct that simplifies MPLANE handling (we discussed that before).

Regards,

	Hans

^ permalink raw reply

* [PATCH 3/3] powerpc/fsl/dts: add FMan node for t1042d4rdb
From: Madalin Bucur @ 2016-11-11 13:59 UTC (permalink / raw)
  To: devicetree; +Cc: oss, linuxppc-dev
In-Reply-To: <1478872784-630-1-git-send-email-madalin.bucur@nxp.com>

Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
---
 arch/powerpc/boot/dts/fsl/t1042d4rdb.dts | 47 ++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/arch/powerpc/boot/dts/fsl/t1042d4rdb.dts b/arch/powerpc/boot/dts/fsl/t1042d4rdb.dts
index 2a5a90d..8c0c318 100644
--- a/arch/powerpc/boot/dts/fsl/t1042d4rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1042d4rdb.dts
@@ -48,6 +48,53 @@
 					"fsl,deepsleep-cpld";
 		};
 	};
+	soc: soc@ffe000000 {
+		fman0: fman@400000 {
+			ethernet@e0000 {
+				phy-handle = <&phy_sgmii_0>;
+				phy-connection-type = "sgmii";
+			};
+
+			ethernet@e2000 {
+				phy-handle = <&phy_sgmii_1>;
+				phy-connection-type = "sgmii";
+			};
+
+			ethernet@e4000 {
+				phy-handle = <&phy_sgmii_2>;
+				phy-connection-type = "sgmii";
+			};
+
+			ethernet@e6000 {
+				phy-handle = <&phy_rgmii_0>;
+				phy-connection-type = "rgmii";
+			};
+
+			ethernet@e8000 {
+				phy-handle = <&phy_rgmii_1>;
+				phy-connection-type = "rgmii";
+			};
+
+			mdio0: mdio@fc000 {
+				phy_sgmii_0: ethernet-phy@02 {
+					reg = <0x02>;
+				};
+				phy_sgmii_1: ethernet-phy@03 {
+					reg = <0x03>;
+				};
+				phy_sgmii_2: ethernet-phy@01 {
+					reg = <0x01>;
+				};
+				phy_rgmii_0: ethernet-phy@04 {
+					reg = <0x04>;
+				};
+				phy_rgmii_1: ethernet-phy@05 {
+					reg = <0x05>;
+				};
+			};
+		};
+	};
+
 };
 
 #include "t1042si-post.dtsi"
-- 
2.1.0

^ permalink raw reply related

* [PATCH 2/3] powerpc/fsl/dts: add QMan and BMan portal nodes on t1024
From: Madalin Bucur @ 2016-11-11 13:59 UTC (permalink / raw)
  To: devicetree; +Cc: oss, linuxppc-dev
In-Reply-To: <1478872784-630-1-git-send-email-madalin.bucur@nxp.com>

Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
---
 arch/powerpc/boot/dts/fsl/t1024qds.dts | 27 +++++++++++++++++++++++++++
 arch/powerpc/boot/dts/fsl/t1024rdb.dts | 31 +++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/arch/powerpc/boot/dts/fsl/t1024qds.dts b/arch/powerpc/boot/dts/fsl/t1024qds.dts
index 772143d..339517e 100644
--- a/arch/powerpc/boot/dts/fsl/t1024qds.dts
+++ b/arch/powerpc/boot/dts/fsl/t1024qds.dts
@@ -41,6 +41,25 @@
 	#size-cells = <2>;
 	interrupt-parent = <&mpic>;
 
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		bman_fbpr: bman-fbpr {
+			size = <0 0x1000000>;
+			alignment = <0 0x1000000>;
+		};
+		qman_fqd: qman-fqd {
+			size = <0 0x400000>;
+			alignment = <0 0x400000>;
+		};
+		qman_pfdr: qman-pfdr {
+			size = <0 0x2000000>;
+			alignment = <0 0x2000000>;
+		};
+	};
+
 	ifc: localbus@ffe124000 {
 		reg = <0xf 0xfe124000 0 0x2000>;
 		ranges = <0 0 0xf 0xe8000000 0x08000000
@@ -80,6 +99,14 @@
 		ranges = <0x00000000 0xf 0x00000000 0x01072000>;
 	};
 
+	bportals: bman-portals@ff4000000 {
+		ranges = <0x0 0xf 0xf4000000 0x2000000>;
+	};
+
+	qportals: qman-portals@ff6000000 {
+		ranges = <0x0 0xf 0xf6000000 0x2000000>;
+	};
+
 	soc: soc@ffe000000 {
 		ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
 		reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/fsl/t1024rdb.dts b/arch/powerpc/boot/dts/fsl/t1024rdb.dts
index 302cdd2..2656095 100644
--- a/arch/powerpc/boot/dts/fsl/t1024rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1024rdb.dts
@@ -41,6 +41,29 @@
 	#size-cells = <2>;
 	interrupt-parent = <&mpic>;
 
+	aliases {
+		sg_2500_aqr105_phy4 = &sg_2500_aqr105_phy4;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		bman_fbpr: bman-fbpr {
+			size = <0 0x1000000>;
+			alignment = <0 0x1000000>;
+		};
+		qman_fqd: qman-fqd {
+			size = <0 0x400000>;
+			alignment = <0 0x400000>;
+		};
+		qman_pfdr: qman-pfdr {
+			size = <0 0x2000000>;
+			alignment = <0 0x2000000>;
+		};
+	};
+
 	ifc: localbus@ffe124000 {
 		reg = <0xf 0xfe124000 0 0x2000>;
 		ranges = <0 0 0xf 0xe8000000 0x08000000
@@ -82,6 +105,14 @@
 		ranges = <0x00000000 0xf 0x00000000 0x01072000>;
 	};
 
+	bportals: bman-portals@ff4000000 {
+		ranges = <0x0 0xf 0xf4000000 0x2000000>;
+	};
+
+	qportals: qman-portals@ff6000000 {
+		ranges = <0x0 0xf 0xf6000000 0x2000000>;
+	};
+
 	soc: soc@ffe000000 {
 		ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
 		reg = <0xf 0xfe000000 0 0x00001000>;
-- 
2.1.0

^ permalink raw reply related

* [PATCH 1/3] powerpc/fsl/dts: add QMan and BMan portal nodes on t1023rdb
From: Madalin Bucur @ 2016-11-11 13:59 UTC (permalink / raw)
  To: devicetree; +Cc: oss, linuxppc-dev

Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
---
 arch/powerpc/boot/dts/fsl/t1023rdb.dts      |  27 ++++++++
 arch/powerpc/boot/dts/fsl/t1023si-post.dtsi | 103 ++++++++++++++++++++++++++++
 2 files changed, 130 insertions(+)

diff --git a/arch/powerpc/boot/dts/fsl/t1023rdb.dts b/arch/powerpc/boot/dts/fsl/t1023rdb.dts
index 2975762..24c9de3 100644
--- a/arch/powerpc/boot/dts/fsl/t1023rdb.dts
+++ b/arch/powerpc/boot/dts/fsl/t1023rdb.dts
@@ -41,6 +41,25 @@
 	#size-cells = <2>;
 	interrupt-parent = <&mpic>;
 
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		bman_fbpr: bman-fbpr {
+			size = <0 0x1000000>;
+			alignment = <0 0x1000000>;
+		};
+		qman_fqd: qman-fqd {
+			size = <0 0x400000>;
+			alignment = <0 0x400000>;
+		};
+		qman_pfdr: qman-pfdr {
+			size = <0 0x2000000>;
+			alignment = <0 0x2000000>;
+		};
+	};
+
 	ifc: localbus@ffe124000 {
 		reg = <0xf 0xfe124000 0 0x2000>;
 		ranges = <0 0 0xf 0xe8000000 0x08000000
@@ -72,6 +91,14 @@
 		ranges = <0x00000000 0xf 0x00000000 0x01072000>;
 	};
 
+	bportals: bman-portals@ff4000000 {
+		ranges = <0x0 0xf 0xf4000000 0x2000000>;
+	};
+
+	qportals: qman-portals@ff6000000 {
+		ranges = <0x0 0xf 0xf6000000 0x2000000>;
+	};
+
 	soc: soc@ffe000000 {
 		ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
 		reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi
index 6e0b489..da2894c 100644
--- a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi
@@ -34,6 +34,21 @@
 
 #include <dt-bindings/thermal/thermal.h>
 
+&bman_fbpr {
+	compatible = "fsl,bman-fbpr";
+	alloc-ranges = <0 0 0x10000 0>;
+};
+
+&qman_fqd {
+	compatible = "fsl,qman-fqd";
+	alloc-ranges = <0 0 0x10000 0>;
+};
+
+&qman_pfdr {
+	compatible = "fsl,qman-pfdr";
+	alloc-ranges = <0 0 0x10000 0>;
+};
+
 &ifc {
 	#address-cells = <2>;
 	#size-cells = <1>;
@@ -180,6 +195,92 @@
 	};
 };
 
+&bportals {
+	#address-cells = <0x1>;
+	#size-cells = <0x1>;
+	compatible = "simple-bus";
+
+	bman-portal@0 {
+		cell-index = <0x0>;
+		compatible = "fsl,bman-portal";
+		reg = <0x0 0x4000>, <0x1000000 0x1000>;
+		interrupts = <105 2 0 0>;
+	};
+	bman-portal@4000 {
+		cell-index = <0x1>;
+		compatible = "fsl,bman-portal";
+		reg = <0x4000 0x4000>, <0x1001000 0x1000>;
+		interrupts = <107 2 0 0>;
+	};
+	bman-portal@8000 {
+		cell-index = <2>;
+		compatible = "fsl,bman-portal";
+		reg = <0x8000 0x4000>, <0x1002000 0x1000>;
+		interrupts = <109 2 0 0>;
+	};
+	bman-portal@c000 {
+		cell-index = <0x3>;
+		compatible = "fsl,bman-portal";
+		reg = <0xc000 0x4000>, <0x1003000 0x1000>;
+		interrupts = <111 2 0 0>;
+	};
+	bman-portal@10000 {
+		cell-index = <0x4>;
+		compatible = "fsl,bman-portal";
+		reg = <0x10000 0x4000>, <0x1004000 0x1000>;
+		interrupts = <113 2 0 0>;
+	};
+	bman-portal@14000 {
+		cell-index = <0x5>;
+		compatible = "fsl,bman-portal";
+		reg = <0x14000 0x4000>, <0x1005000 0x1000>;
+		interrupts = <115 2 0 0>;
+	};
+};
+
+&qportals {
+	#address-cells = <0x1>;
+	#size-cells = <0x1>;
+	compatible = "simple-bus";
+
+	qportal0: qman-portal@0 {
+		compatible = "fsl,qman-portal";
+		reg = <0x0 0x4000>, <0x1000000 0x1000>;
+		interrupts = <104 0x2 0 0>;
+		cell-index = <0x0>;
+	};
+	qportal1: qman-portal@4000 {
+		compatible = "fsl,qman-portal";
+		reg = <0x4000 0x4000>, <0x1001000 0x1000>;
+		interrupts = <106 0x2 0 0>;
+		cell-index = <0x1>;
+	};
+	qportal2: qman-portal@8000 {
+		compatible = "fsl,qman-portal";
+		reg = <0x8000 0x4000>, <0x1002000 0x1000>;
+		interrupts = <108 0x2 0 0>;
+		cell-index = <0x2>;
+	};
+	qportal3: qman-portal@c000 {
+		compatible = "fsl,qman-portal";
+		reg = <0xc000 0x4000>, <0x1003000 0x1000>;
+		interrupts = <110 0x2 0 0>;
+		cell-index = <0x3>;
+	};
+	qportal4: qman-portal@10000 {
+		compatible = "fsl,qman-portal";
+		reg = <0x10000 0x4000>, <0x1004000 0x1000>;
+		interrupts = <112 0x2 0 0>;
+		cell-index = <0x4>;
+	};
+	qportal5: qman-portal@14000 {
+		compatible = "fsl,qman-portal";
+		reg = <0x14000 0x4000>, <0x1005000 0x1000>;
+		interrupts = <114 0x2 0 0>;
+		cell-index = <0x5>;
+	};
+};
+
 &soc {
 	#address-cells = <1>;
 	#size-cells = <1>;
@@ -413,6 +514,8 @@
 	};
 
 /include/ "qoriq-sec5.0-0.dtsi"
+/include/ "qoriq-qman3.dtsi"
+/include/ "qoriq-bman1.dtsi"
 
 /include/ "qoriq-fman3l-0.dtsi"
 /include/ "qoriq-fman3-0-10g-0-best-effort.dtsi"
-- 
2.1.0

^ permalink raw reply related

* Re: [PATCH 2/5] media: i2c: max2175: Add MAX2175 support
From: Hans Verkuil @ 2016-11-11 13:58 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Ramesh Shanmugasundaram, robh+dt, mark.rutland, mchehab,
	sakari.ailus, crope, chris.paterson2, geert+renesas, linux-media,
	devicetree, linux-renesas-soc
In-Reply-To: <1903855.3Xg5AI8ucK@avalon>

On 11/11/2016 02:48 PM, Laurent Pinchart wrote:
> Hi Hans,
> 
> On Friday 11 Nov 2016 14:21:22 Hans Verkuil wrote:
>> On 11/09/2016 04:44 PM, Ramesh Shanmugasundaram wrote:
>>> This patch adds driver support for MAX2175 chip. This is Maxim
>>> Integrated's RF to Bits tuner front end chip designed for software-defined
>>> radio solutions. This driver exposes the tuner as a sub-device instance
>>> with standard and custom controls to configure the device.
>>>
>>> Signed-off-by: Ramesh Shanmugasundaram
>>> <ramesh.shanmugasundaram@bp.renesas.com> ---
>>>
>>>  .../devicetree/bindings/media/i2c/max2175.txt      |   61 +
>>>  drivers/media/i2c/Kconfig                          |    4 +
>>>  drivers/media/i2c/Makefile                         |    2 +
>>>  drivers/media/i2c/max2175/Kconfig                  |    8 +
>>>  drivers/media/i2c/max2175/Makefile                 |    4 +
>>>  drivers/media/i2c/max2175/max2175.c                | 1558 +++++++++++++++
>>>  drivers/media/i2c/max2175/max2175.h                |  108 ++
>>>  7 files changed, 1745 insertions(+)
>>>  create mode 100644
>>>  Documentation/devicetree/bindings/media/i2c/max2175.txt
>>>  create mode 100644 drivers/media/i2c/max2175/Kconfig
>>>  create mode 100644 drivers/media/i2c/max2175/Makefile
>>>  create mode 100644 drivers/media/i2c/max2175/max2175.c
>>>  create mode 100644 drivers/media/i2c/max2175/max2175.h
>>
>> <snip>
>>
>>> diff --git a/drivers/media/i2c/max2175/max2175.c
>>> b/drivers/media/i2c/max2175/max2175.c new file mode 100644
>>> index 0000000..ec45b52
>>> --- /dev/null
>>> +++ b/drivers/media/i2c/max2175/max2175.c
>>> @@ -0,0 +1,1558 @@
>>
>> <snip>
>>
>>> +/* Read/Write bit(s) on top of regmap */
>>> +static int max2175_read(struct max2175 *ctx, u8 idx, u8 *val)
>>> +{
>>> +	u32 regval;
>>> +	int ret = regmap_read(ctx->regmap, idx, &regval);
>>> +
>>> +	if (ret)
>>> +		v4l2_err(ctx->client, "read ret(%d): idx 0x%02x\n", ret, idx);
> 
> By the way, I think I've seen a proposal to get rid of v4l2_err() in favour of 
> dev_err(), was I dreaming or should this patch use dev_err() already ?

I haven't seen anything, but I may have missed it. I haven't been on top of the
mailinglist lately. I'm fine with both.

> 
>>> +
>>> +	*val = regval;
>>
>> Does regmap_read initialize regval even if it returns an error? If not,
>> then I would initialize regval to 0 to prevent *val being uninitialized.
> 
> Better than that the error should be propagated to the caller and handled.
> 
>>> +	return ret;
>>> +}
> 
> [snip]
> 
>>> +static int max2175_band_from_freq(u32 freq)
>>> +{
>>> +	if (freq >= 144000 && freq <= 26100000)
>>> +		return MAX2175_BAND_AM;
>>> +	else if (freq >= 65000000 && freq <= 108000000)
>>> +		return MAX2175_BAND_FM;
>>> +	else
>>
>> No need for these 'else' keywords.
> 
> Indeed by in my opinion they improve readability :-)
> 
>>> +		return MAX2175_BAND_VHF;
>>> +}
> 
> [snip]
> 
>>> +static const struct v4l2_ctrl_config max2175_na_rx_mode = {
>>> +	.ops = &max2175_ctrl_ops,
>>> +	.id = V4L2_CID_MAX2175_RX_MODE,
>>> +	.name = "RX MODE",
>>> +	.type = V4L2_CTRL_TYPE_MENU,
>>> +	.max = ARRAY_SIZE(max2175_ctrl_na_rx_modes) - 1,
>>> +	.def = 0,
>>> +	.qmenu = max2175_ctrl_na_rx_modes,
>>> +};
>>
>> Please document all these controls better. This is part of the public API,
>> so you need to give more information what this means exactly.
> 
> Should that go to Documentation/media/v4l-drivers/ ? If so "[PATCH v4 3/4] 
> v4l: Add Renesas R-Car FDP1 Driver" can be used as an example.

I think that's the preferred place going forward. But a comment should be
added here pointing to that file so there is a better chance of keeping
the doc and code in sync.

> 
> [snip]
> 

	Hans

^ permalink raw reply

* Re: [RFC 5/5] doc_rst: media: New SDR formats SC16, SC18 & SC20
From: Laurent Pinchart @ 2016-11-11 13:57 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Ramesh Shanmugasundaram, Antti Palosaari,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	mark.rutland-5wv7dgnIgG8@public.gmane.org,
	mchehab-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org,
	Chris Paterson, geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org,
	linux-media-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <8438b944-216e-3237-c312-92a674fd4541-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>

Hi Hans,

On Friday 11 Nov 2016 14:53:58 Hans Verkuil wrote:
> On 11/10/2016 09:08 AM, Laurent Pinchart wrote:
> > Antti, Hans, ping ? Please see below.
> > 
> > On Friday 04 Nov 2016 09:23:29 Ramesh Shanmugasundaram wrote:
> >>> On 11/02/2016 10:58 PM, Laurent Pinchart wrote:
> >>>> On Wednesday 02 Nov 2016 09:00:00 Ramesh Shanmugasundaram wrote:
> >>>>>>> On Wednesday 12 Oct 2016 15:10:29 Ramesh Shanmugasundaram wrote:
> >>>>>>>> This patch adds documentation for the three new SDR formats
> >>>>>>>> 
> >>>>>>>> V4L2_SDR_FMT_SCU16BE
> >>>>>>>> V4L2_SDR_FMT_SCU18BE
> >>>>>>>> V4L2_SDR_FMT_SCU20BE
> >>>>> 
> >>>>> [snip]
> >>>>> 
> >>>>>>>> +
> >>>>>>>> +       -  start + 0:
> >>>>>>>> +
> >>>>>>>> +       -  I'\ :sub:`0[D13:D6]`
> >>>>>>>> +
> >>>>>>>> +       -  I'\ :sub:`0[D5:D0]`
> >>>>>>>> +
> >>>>>>>> +    -  .. row 2
> >>>>>>>> +
> >>>>>>>> +       -  start + buffer_size/2:
> >>>>>>>> +
> >>>>>>>> +       -  Q'\ :sub:`0[D13:D6]`
> >>>>>>>> +
> >>>>>>>> +       -  Q'\ :sub:`0[D5:D0]`
> >>>>>>> 
> >>>>>>> The format looks planar, does it use one V4L2 plane (as does NV12)
> >>>>>>> or two V4L2 planes (as does NV12M) ? Same question for the other
> >>>>>>> formats.
> >>>>>> 
> >>>>>> Thank you for bringing up this topic. This is one of the key design
> >>>>>> dilemma.
> >>>>>> 
> >>>>>> The I & Q data for these three SDR formats comes from two different
> >>>>>> DMA channels and hence two separate pointers -> we could say it is
> >>>>>> v4l2 multi- planar. Right now, I am making it look like a single
> >>>>>> plane by presenting the data in one single buffer ptr.
> >>>>>> 
> >>>>>> For e.g. multi-planar SC16 format would look something like this
> >>>>>> 
> >>>>>> <------------------------32bits---------------------->
> >>>>>> <--I(14 bit data) + 2bit status--16bit padded zeros--> : start0 + 0
> >>>>>> <--I(14 bit data) + 2bit status--16bit padded zeros--> : start0 + 4
> >>>>>> ...
> >>>>>> <--Q(14 bit data) + 2bit status--16bit padded zeros--> : start1 + 0
> >>>>>> <--Q(14 bit data) + 2bit status--16bit padded zeros--> : start1 + 4
> >>>>>> 
> >>>>>> My concerns are
> >>>>>> 
> >>>>>> 1) These formats are not a standard as the video "Image Formats".
> >>>>>> These formats are possible when we use DRIF + MAX2175 combination.
> >>>>>> If we interface with a different tuner vendor, the above format(s)
> >>>>>> MAY/MAY NOT be re-usable. We do not know at this point. This is the
> >>>>>> main open item for discussion in the cover letter.
> >>>> 
> >>>> If the formats are really device-specific then they should be
> >>>> documented accordingly and not made generic.
> >>>> 
> >>>>>> 2) MPLANE support within V4L2 seems specific to video. Please
> >>>>>> correct me if this is wrong interpretation.
> >>>>>> 
> >>>>>> - struct v4l2_format contains v4l2_sdr_format and
> >>>>>> v4l2_pix_format_mplane as members of union. Should I create a new
> >>>>>> v4l2_sdr_format_mplane? If I have to use v4l2_pix_format_mplane most
> >>>>>> of the video specific members would be unused (it would be similar
> >>>>>> to using v4l2_pix_format itself instead of v4l2_sdr_format)?
> >>>> 
> >>>> I have no answer to that question as I'm not familiar with SDR. Antti,
> >>>> you've added v4l2_sdr_format to the API, what's your opinion ? Hans,
> >>>> as you've acked the patch, your input would be appreciated as well.
> >>> 
> >>> If I understood correctly this hardware provides I and Q samples via
> >>> different channels and driver now combines those channels as a
> >>> sequential
> >>> IQ sample pairs.
> >> 
> >> The driver combines the two buffer ptrs and present as one single buffer.
> >> For a buffer of size 200
> >> 
> >> ptr + 0   : I I I I ... I
> >> ptr + 100 : Q Q Q Q ... Q
> >> 
> >>> I have never seen any other than hw which provides IQ IQ IQ IQ ... IQ.
> >> 
> >> There are some modes where this h/w combo can also do IQ IQ IQ pattern.
> >> Those modes are not added in the RFC patchset.
> >> 
> >>> This is
> >>> I I I I ... I
> >>> Q Q Q Q ... Q
> >>> I am not very familiar with planars, but it sounds like it is correct
> >>> approach. So I think should be added rather than emulate packet
> >>> sequential format.
> >> 
> >> My understanding of V4L2 MPLANE constructs is limited to a quick code
> >> read
> >> only. At this point MPLANE support seems specific to video. SDR is
> >> defined
> >> as separate format like v4l2_pix_format. Questions would be - should we
> >> define new SDR_MPLANE? or merge SDR format with pix format & reuse
> >> existing
> >> MPLANE with some SDR extensions (if possible)? These seem big design
> >> decisions. Any suggestions please?
> >> 
> >> For my use case, MPLANE support does not seem to add significant benefit
> >> except it may be syntactically correct. I am doing cyclic DMA with a
> >> small
> >> set of h/w buffers and copying each stage to one mmapped vmalloc
> >> vb2_buffer
> >> at two offsets. If we add MPLANE support, it can be two non-contiguous
> >> buffer pointers.
> >> 
> >>>>>> - The above decision (accomodate SDR & MPLANE) needs to be
> >>>>>> propagated across the framework. Is this the preferred approach?
> >>>>>> 
> >>>>>> It goes back to point (1). As of today, the change set for this
> >>>>>> combo (DRIF+MAX2175) introduces new SDR formats only. Should it add
> >>>>>> further SDR+MPLANE support to the framework as well?
> >>>>>> 
> >>>>>> I would appreciate your suggestions on this regard.
> 
> Some terminology first:
> 
> Planar formats separate the data into different memory areas: in this case
> one part is all I and one part is all Q. This as opposed to interleaved
> formats (IQIQIQIQ....).
> 
> As long as both planes fit in the same buffer all is fine. Since that is
> the case here there is no need to introduce a new MPLANE API.
> 
> The MPLANE API was added for video to handle cases where the two planes
> had to be in two different non-contiguous buffers.

Not only that, it can also be used for cases where storing the two planes in 
separate buffers can be beneficial, even if a single contiguous buffer could 
work.

> So instead of passing one buffer pointer, you need to pass two or more
> buffer pointers.
> 
> In hindsight we should have called it the MBUFFER API.

The name was badly chosen, yes.

> Oh well...
> 
> Anyway, since there is no problem here apparently to keep both planes
> in one buffer there is also no need to introduce a SDR_MPLANE.

The question here is whether there could be a benefit in separating I and Q 
data in two buffers compared to storing them in the same buffer.

-- 
Regards,

Laurent Pinchart

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [RFC 5/5] doc_rst: media: New SDR formats SC16, SC18 & SC20
From: Hans Verkuil @ 2016-11-11 13:53 UTC (permalink / raw)
  To: Laurent Pinchart, Ramesh Shanmugasundaram
  Cc: Antti Palosaari, robh+dt@kernel.org, mark.rutland@arm.com,
	mchehab@kernel.org, sakari.ailus@linux.intel.com, Chris Paterson,
	geert@linux-m68k.org, linux-media@vger.kernel.org,
	devicetree@vger.kernel.org, linux-renesas-soc@vger.kernel.org
In-Reply-To: <1805711.Tm0TqcXx1h@avalon>

On 11/10/2016 09:08 AM, Laurent Pinchart wrote:
> Antti, Hans, ping ? Please see below.
> 
> On Friday 04 Nov 2016 09:23:29 Ramesh Shanmugasundaram wrote:
>>> On 11/02/2016 10:58 PM, Laurent Pinchart wrote:
>>>> On Wednesday 02 Nov 2016 09:00:00 Ramesh Shanmugasundaram wrote:
>>>>>>> On Wednesday 12 Oct 2016 15:10:29 Ramesh Shanmugasundaram wrote:
>>>>>>>
>>>>>>>> This patch adds documentation for the three new SDR formats
>>>>>>>>
>>>>>>>> V4L2_SDR_FMT_SCU16BE
>>>>>>>> V4L2_SDR_FMT_SCU18BE
>>>>>>>> V4L2_SDR_FMT_SCU20BE
>>>>>
>>>>> [snip]
>>>>>
>>>>>>>> +
>>>>>>>> +       -  start + 0:
>>>>>>>> +
>>>>>>>> +       -  I'\ :sub:`0[D13:D6]`
>>>>>>>> +
>>>>>>>> +       -  I'\ :sub:`0[D5:D0]`
>>>>>>>> +
>>>>>>>> +    -  .. row 2
>>>>>>>> +
>>>>>>>> +       -  start + buffer_size/2:
>>>>>>>> +
>>>>>>>> +       -  Q'\ :sub:`0[D13:D6]`
>>>>>>>> +
>>>>>>>> +       -  Q'\ :sub:`0[D5:D0]`
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> The format looks planar, does it use one V4L2 plane (as does NV12)
>>>>>>> or two V4L2 planes (as does NV12M) ? Same question for the other
>>>>>>> formats.
>>>>>>
>>>>>> Thank you for bringing up this topic. This is one of the key design
>>>>>> dilemma.
>>>>>>
>>>>>> The I & Q data for these three SDR formats comes from two different
>>>>>> DMA channels and hence two separate pointers -> we could say it is
>>>>>> v4l2 multi- planar. Right now, I am making it look like a single
>>>>>> plane by presenting the data in one single buffer ptr.
>>>>>>
>>>>>> For e.g. multi-planar SC16 format would look something like this
>>>>>>
>>>>>> <------------------------32bits---------------------->
>>>>>> <--I(14 bit data) + 2bit status--16bit padded zeros--> : start0 + 0
>>>>>> <--I(14 bit data) + 2bit status--16bit padded zeros--> : start0 + 4
>>>>>> ...
>>>>>> <--Q(14 bit data) + 2bit status--16bit padded zeros--> : start1 + 0
>>>>>> <--Q(14 bit data) + 2bit status--16bit padded zeros--> : start1 + 4
>>>>>>
>>>>>> My concerns are
>>>>>>
>>>>>> 1) These formats are not a standard as the video "Image Formats".
>>>>>> These formats are possible when we use DRIF + MAX2175 combination.
>>>>>> If we interface with a different tuner vendor, the above format(s)
>>>>>> MAY/MAY NOT be re-usable. We do not know at this point. This is the
>>>>>> main open item for discussion in the cover letter.
>>>>
>>>> If the formats are really device-specific then they should be
>>>> documented accordingly and not made generic.
>>>>
>>>>>> 2) MPLANE support within V4L2 seems specific to video. Please
>>>>>> correct me if this is wrong interpretation.
>>>>>>
>>>>>> - struct v4l2_format contains v4l2_sdr_format and
>>>>>> v4l2_pix_format_mplane as members of union. Should I create a new
>>>>>> v4l2_sdr_format_mplane? If I have to use v4l2_pix_format_mplane most
>>>>>> of the video specific members would be unused (it would be similar
>>>>>> to using v4l2_pix_format itself instead of v4l2_sdr_format)?
>>>>
>>>> I have no answer to that question as I'm not familiar with SDR. Antti,
>>>> you've added v4l2_sdr_format to the API, what's your opinion ? Hans,
>>>> as you've acked the patch, your input would be appreciated as well.
>>>
>>> If I understood correctly this hardware provides I and Q samples via
>>> different channels and driver now combines those channels as a sequential
>>> IQ sample pairs. 
>>
>> The driver combines the two buffer ptrs and present as one single buffer.
>> For a buffer of size 200
>>
>> ptr + 0   : I I I I ... I
>> ptr + 100 : Q Q Q Q ... Q
>>
>>> I have never seen any other than hw which provides IQ IQ IQ IQ ... IQ.
>>
>> There are some modes where this h/w combo can also do IQ IQ IQ pattern.
>> Those modes are not added in the RFC patchset.
>>
>>> This is
>>> I I I I ... I
>>> Q Q Q Q ... Q
>>> I am not very familiar with planars, but it sounds like it is correct
>>> approach. So I think should be added rather than emulate packet
>>> sequential format.
>>
>> My understanding of V4L2 MPLANE constructs is limited to a quick code read
>> only. At this point MPLANE support seems specific to video. SDR is defined
>> as separate format like v4l2_pix_format. Questions would be - should we
>> define new SDR_MPLANE? or merge SDR format with pix format & reuse existing
>> MPLANE with some SDR extensions (if possible)? These seem big design
>> decisions. Any suggestions please?
>>
>> For my use case, MPLANE support does not seem to add significant benefit
>> except it may be syntactically correct. I am doing cyclic DMA with a small
>> set of h/w buffers and copying each stage to one mmapped vmalloc vb2_buffer
>> at two offsets. If we add MPLANE support, it can be two non-contiguous
>> buffer pointers. 
>>
>>>>>> - The above decision (accomodate SDR & MPLANE) needs to be
>>>>>> propagated across the framework. Is this the preferred approach?
>>>>>>
>>>>>> It goes back to point (1). As of today, the change set for this
>>>>>> combo (DRIF+MAX2175) introduces new SDR formats only. Should it add
>>>>>> further SDR+MPLANE support to the framework as well?
>>>>>>
>>>>>> I would appreciate your suggestions on this regard.
> 

Some terminology first:

Planar formats separate the data into different memory areas: in this case
one part is all I and one part is all Q. This as opposed to interleaved
formats (IQIQIQIQ....).

As long as both planes fit in the same buffer all is fine. Since that is
the case here there is no need to introduce a new MPLANE API.

The MPLANE API was added for video to handle cases where the two planes
had to be in two different non-contiguous buffers.

So instead of passing one buffer pointer, you need to pass two or more
buffer pointers.

In hindsight we should have called it the MBUFFER API.

Oh well...

Anyway, since there is no problem here apparently to keep both planes
in one buffer there is also no need to introduce a SDR_MPLANE.

Regards,

	Hans

^ permalink raw reply

* Re: [PATCH 3/5] media: Add new SDR formats SC16, SC18 & SC20
From: Laurent Pinchart @ 2016-11-11 13:49 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Ramesh Shanmugasundaram, robh+dt, mark.rutland, mchehab,
	sakari.ailus, crope, chris.paterson2, geert+renesas, linux-media,
	devicetree, linux-renesas-soc
In-Reply-To: <502a606c-2d66-4257-af17-7b7f35f2c839@xs4all.nl>

Hi Hans,

On Friday 11 Nov 2016 14:24:41 Hans Verkuil wrote:
> On 11/09/2016 04:44 PM, Ramesh Shanmugasundaram wrote:
> > This patch adds support for the three new SDR formats. These formats
> > were prefixed with "sliced" indicating I data constitutes the top half and
> > Q data constitutes the bottom half of the received buffer.
> 
> The standard terminology for video formats is "planar". I am leaning towards
> using that here as well.

Another important question is whether we should introduce an SDR planar API. 
That's what we would like your opinion on.

> > V4L2_SDR_FMT_SCU16BE - 14-bit complex (I & Q) unsigned big-endian sample
> > inside 16-bit. V4L2 FourCC: SC16
> > 
> > V4L2_SDR_FMT_SCU18BE - 16-bit complex (I & Q) unsigned big-endian sample
> > inside 18-bit. V4L2 FourCC: SC18
> > 
> > V4L2_SDR_FMT_SCU20BE - 18-bit complex (I & Q) unsigned big-endian sample
> > inside 20-bit. V4L2 FourCC: SC20
> > 
> > Signed-off-by: Ramesh Shanmugasundaram
> > <ramesh.shanmugasundaram@bp.renesas.com> ---
> > 
> >  drivers/media/v4l2-core/v4l2-ioctl.c | 3 +++
> >  include/uapi/linux/videodev2.h       | 3 +++
> >  2 files changed, 6 insertions(+)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c
> > b/drivers/media/v4l2-core/v4l2-ioctl.c index 181381d..d36b386 100644
> > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > @@ -1207,6 +1207,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc
> > *fmt)> 
> >  	case V4L2_SDR_FMT_CS8:		descr = "Complex S8"; break;
> >  	case V4L2_SDR_FMT_CS14LE:	descr = "Complex S14LE"; break;
> >  	case V4L2_SDR_FMT_RU12LE:	descr = "Real U12LE"; break;
> > 
> > +	case V4L2_SDR_FMT_SCU16BE:	descr = "Sliced Complex U16BE"; break;
> > +	case V4L2_SDR_FMT_SCU18BE:	descr = "Sliced Complex U18BE"; break;
> > +	case V4L2_SDR_FMT_SCU20BE:	descr = "Sliced Complex U20BE"; break;
> > 
> >  	case V4L2_TCH_FMT_DELTA_TD16:	descr = "16-bit signed deltas"; break;
> >  	case V4L2_TCH_FMT_DELTA_TD08:	descr = "8-bit signed deltas"; break;
> >  	case V4L2_TCH_FMT_TU16:		descr = "16-bit unsigned touch data"; 
break;
> > 
> > diff --git a/include/uapi/linux/videodev2.h
> > b/include/uapi/linux/videodev2.h index 4364ce6..34a9c30 100644
> > --- a/include/uapi/linux/videodev2.h
> > +++ b/include/uapi/linux/videodev2.h
> > @@ -666,6 +666,9 @@ struct v4l2_pix_format {
> > 
> >  #define V4L2_SDR_FMT_CS8          v4l2_fourcc('C', 'S', '0', '8') /*
> >  complex s8 */ #define V4L2_SDR_FMT_CS14LE       v4l2_fourcc('C', 'S',
> >  '1', '4') /* complex s14le */ #define V4L2_SDR_FMT_RU12LE      
> >  v4l2_fourcc('R', 'U', '1', '2') /* real u12le */> 
> > +#define V4L2_SDR_FMT_SCU16BE	  v4l2_fourcc('S', 'C', '1', '6') /* 
sliced
> > complex u16be */ +#define V4L2_SDR_FMT_SCU18BE	  v4l2_fourcc('S', 
'C',
> > '1', '8') /* sliced complex u18be */ +#define V4L2_SDR_FMT_SCU20BE	 
> > v4l2_fourcc('S', 'C', '2', '0') /* sliced complex u20be */> 
> >  /* Touch formats - used for Touch devices */
> >  #define V4L2_TCH_FMT_DELTA_TD16	v4l2_fourcc('T', 'D', '1', '6') /* 16-
bit
> >  signed deltas */

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* Re: [PATCH 3/5] media: Add new SDR formats SC16, SC18 & SC20
From: Laurent Pinchart @ 2016-11-11 13:48 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Ramesh Shanmugasundaram, robh+dt, mark.rutland, mchehab,
	sakari.ailus, crope, chris.paterson2, geert+renesas, linux-media,
	devicetree, linux-renesas-soc
In-Reply-To: <502a606c-2d66-4257-af17-7b7f35f2c839@xs4all.nl>

Hi Hans,

On Friday 11 Nov 2016 14:24:41 Hans Verkuil wrote:
> On 11/09/2016 04:44 PM, Ramesh Shanmugasundaram wrote:
> > This patch adds support for the three new SDR formats. These formats
> > were prefixed with "sliced" indicating I data constitutes the top half and
> > Q data constitutes the bottom half of the received buffer.
> 
> The standard terminology for video formats is "planar". I am leaning towards
> using that here as well.
> 
> Any opinions on this?

I like that as well, but I'm obviously biased :-)

> > V4L2_SDR_FMT_SCU16BE - 14-bit complex (I & Q) unsigned big-endian sample
> > inside 16-bit. V4L2 FourCC: SC16
> > 
> > V4L2_SDR_FMT_SCU18BE - 16-bit complex (I & Q) unsigned big-endian sample
> > inside 18-bit. V4L2 FourCC: SC18
> > 
> > V4L2_SDR_FMT_SCU20BE - 18-bit complex (I & Q) unsigned big-endian sample
> > inside 20-bit. V4L2 FourCC: SC20
> > 
> > Signed-off-by: Ramesh Shanmugasundaram
> > <ramesh.shanmugasundaram@bp.renesas.com> ---
> > 
> >  drivers/media/v4l2-core/v4l2-ioctl.c | 3 +++
> >  include/uapi/linux/videodev2.h       | 3 +++
> >  2 files changed, 6 insertions(+)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c
> > b/drivers/media/v4l2-core/v4l2-ioctl.c index 181381d..d36b386 100644
> > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > @@ -1207,6 +1207,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc
> > *fmt)> 
> >  	case V4L2_SDR_FMT_CS8:		descr = "Complex S8"; break;
> >  	case V4L2_SDR_FMT_CS14LE:	descr = "Complex S14LE"; break;
> >  	case V4L2_SDR_FMT_RU12LE:	descr = "Real U12LE"; break;
> > 
> > +	case V4L2_SDR_FMT_SCU16BE:	descr = "Sliced Complex U16BE"; break;
> > +	case V4L2_SDR_FMT_SCU18BE:	descr = "Sliced Complex U18BE"; break;
> > +	case V4L2_SDR_FMT_SCU20BE:	descr = "Sliced Complex U20BE"; break;
> > 
> >  	case V4L2_TCH_FMT_DELTA_TD16:	descr = "16-bit signed deltas"; break;
> >  	case V4L2_TCH_FMT_DELTA_TD08:	descr = "8-bit signed deltas"; break;
> >  	case V4L2_TCH_FMT_TU16:		descr = "16-bit unsigned touch data"; 
break;
> > 
> > diff --git a/include/uapi/linux/videodev2.h
> > b/include/uapi/linux/videodev2.h index 4364ce6..34a9c30 100644
> > --- a/include/uapi/linux/videodev2.h
> > +++ b/include/uapi/linux/videodev2.h
> > @@ -666,6 +666,9 @@ struct v4l2_pix_format {
> > 
> >  #define V4L2_SDR_FMT_CS8          v4l2_fourcc('C', 'S', '0', '8') /*
> >  complex s8 */ #define V4L2_SDR_FMT_CS14LE       v4l2_fourcc('C', 'S',
> >  '1', '4') /* complex s14le */ #define V4L2_SDR_FMT_RU12LE      
> >  v4l2_fourcc('R', 'U', '1', '2') /* real u12le */> 
> > +#define V4L2_SDR_FMT_SCU16BE	  v4l2_fourcc('S', 'C', '1', '6') /* 
sliced
> > complex u16be */ +#define V4L2_SDR_FMT_SCU18BE	  v4l2_fourcc('S', 
'C',
> > '1', '8') /* sliced complex u18be */ +#define V4L2_SDR_FMT_SCU20BE	 
> > v4l2_fourcc('S', 'C', '2', '0') /* sliced complex u20be */> 
> >  /* Touch formats - used for Touch devices */
> >  #define V4L2_TCH_FMT_DELTA_TD16	v4l2_fourcc('T', 'D', '1', '6') /* 16-
bit
> >  signed deltas */

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* Re: [PATCH 2/5] media: i2c: max2175: Add MAX2175 support
From: Laurent Pinchart @ 2016-11-11 13:48 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Ramesh Shanmugasundaram, robh+dt, mark.rutland, mchehab,
	sakari.ailus, crope, chris.paterson2, geert+renesas, linux-media,
	devicetree, linux-renesas-soc
In-Reply-To: <46394837-c3f0-8487-750b-95dae7bcf859@xs4all.nl>

Hi Hans,

On Friday 11 Nov 2016 14:21:22 Hans Verkuil wrote:
> On 11/09/2016 04:44 PM, Ramesh Shanmugasundaram wrote:
> > This patch adds driver support for MAX2175 chip. This is Maxim
> > Integrated's RF to Bits tuner front end chip designed for software-defined
> > radio solutions. This driver exposes the tuner as a sub-device instance
> > with standard and custom controls to configure the device.
> > 
> > Signed-off-by: Ramesh Shanmugasundaram
> > <ramesh.shanmugasundaram@bp.renesas.com> ---
> > 
> >  .../devicetree/bindings/media/i2c/max2175.txt      |   61 +
> >  drivers/media/i2c/Kconfig                          |    4 +
> >  drivers/media/i2c/Makefile                         |    2 +
> >  drivers/media/i2c/max2175/Kconfig                  |    8 +
> >  drivers/media/i2c/max2175/Makefile                 |    4 +
> >  drivers/media/i2c/max2175/max2175.c                | 1558 +++++++++++++++
> >  drivers/media/i2c/max2175/max2175.h                |  108 ++
> >  7 files changed, 1745 insertions(+)
> >  create mode 100644
> >  Documentation/devicetree/bindings/media/i2c/max2175.txt
> >  create mode 100644 drivers/media/i2c/max2175/Kconfig
> >  create mode 100644 drivers/media/i2c/max2175/Makefile
> >  create mode 100644 drivers/media/i2c/max2175/max2175.c
> >  create mode 100644 drivers/media/i2c/max2175/max2175.h
> 
> <snip>
> 
> > diff --git a/drivers/media/i2c/max2175/max2175.c
> > b/drivers/media/i2c/max2175/max2175.c new file mode 100644
> > index 0000000..ec45b52
> > --- /dev/null
> > +++ b/drivers/media/i2c/max2175/max2175.c
> > @@ -0,0 +1,1558 @@
> 
> <snip>
> 
> > +/* Read/Write bit(s) on top of regmap */
> > +static int max2175_read(struct max2175 *ctx, u8 idx, u8 *val)
> > +{
> > +	u32 regval;
> > +	int ret = regmap_read(ctx->regmap, idx, &regval);
> > +
> > +	if (ret)
> > +		v4l2_err(ctx->client, "read ret(%d): idx 0x%02x\n", ret, idx);

By the way, I think I've seen a proposal to get rid of v4l2_err() in favour of 
dev_err(), was I dreaming or should this patch use dev_err() already ?

> > +
> > +	*val = regval;
> 
> Does regmap_read initialize regval even if it returns an error? If not,
> then I would initialize regval to 0 to prevent *val being uninitialized.

Better than that the error should be propagated to the caller and handled.

> > +	return ret;
> > +}

[snip]

> > +static int max2175_band_from_freq(u32 freq)
> > +{
> > +	if (freq >= 144000 && freq <= 26100000)
> > +		return MAX2175_BAND_AM;
> > +	else if (freq >= 65000000 && freq <= 108000000)
> > +		return MAX2175_BAND_FM;
> > +	else
> 
> No need for these 'else' keywords.

Indeed by in my opinion they improve readability :-)

> > +		return MAX2175_BAND_VHF;
> > +}

[snip]

> > +static const struct v4l2_ctrl_config max2175_na_rx_mode = {
> > +	.ops = &max2175_ctrl_ops,
> > +	.id = V4L2_CID_MAX2175_RX_MODE,
> > +	.name = "RX MODE",
> > +	.type = V4L2_CTRL_TYPE_MENU,
> > +	.max = ARRAY_SIZE(max2175_ctrl_na_rx_modes) - 1,
> > +	.def = 0,
> > +	.qmenu = max2175_ctrl_na_rx_modes,
> > +};
> 
> Please document all these controls better. This is part of the public API,
> so you need to give more information what this means exactly.

Should that go to Documentation/media/v4l-drivers/ ? If so "[PATCH v4 3/4] 
v4l: Add Renesas R-Car FDP1 Driver" can be used as an example.

[snip]

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* RE: [PATCH V5 3/3] ARM64 LPC: LPC driver implementation on Hip06
From: Gabriele Paoloni @ 2016-11-11 13:39 UTC (permalink / raw)
  To: Arnd Bergmann, Gabriele Paoloni
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	Yuanzhichang, mark.rutland-5wv7dgnIgG8@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org,
	minyard-HInyCGIudOg@public.gmane.org,
	linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org,
	John Garry, will.deacon-5wv7dgnIgG8@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, xuwei (O),
	Linuxarm, zourongrong-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	kantyzc-9Onoh4P/yGk@public.gmane.org
In-Reply-To: <10334260.ztLXZ2Oynd@wuerfel>

Hi Arnd

> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd-r2nGTMty4D4@public.gmane.org]
> Sent: 10 November 2016 16:07
> To: Gabriele Paoloni
> Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org; Yuanzhichang;
> mark.rutland-5wv7dgnIgG8@public.gmane.org; devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org;
> lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org; minyard-HInyCGIudOg@public.gmane.org; linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org;
> benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org; John Garry; will.deacon-5wv7dgnIgG8@public.gmane.org; linux-
> kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; xuwei (O); Linuxarm; zourongrong-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org;
> robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org; kantyzc-9Onoh4P/yGk@public.gmane.org; linux-serial-u79uwXL29TY76Z2rM5mHXA@public.gmane.org;
> catalin.marinas-5wv7dgnIgG8@public.gmane.org; olof-nZhT3qVonbNeoWH0uzbU5w@public.gmane.org; liviu.dudau-5wv7dgnIgG8@public.gmane.org;
> bhelgaas@googl e.com; zhichang.yuan02-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
> Subject: Re: [PATCH V5 3/3] ARM64 LPC: LPC driver implementation on
> Hip06
> 
> On Thursday, November 10, 2016 3:36:49 PM CET Gabriele Paoloni wrote:
> >
> > Where should we get the range from? For LPC we know that it is going
> > Work on anything that is not used by PCI I/O space, and this is
> > why we use [0, PCIBIOS_MIN_IO]
> 
> It should be allocated the same way we allocate PCI config space
> segments. This is currently done with the io_range list in
> drivers/pci/pci.c, which isn't perfect but could be extended
> if necessary. Based on what others commented here, I'd rather
> make the differences between ISA/LPC and PCI I/O ranges smaller
> than larger.

I am not sure this would make sense...

IMHO all the mechanism around io_range_list is needed to provide the
"mapping" between I/O tokens and physical CPU addresses.

Currently the available tokens range from 0 to IO_SPACE_LIMIT.

As you know the I/O memory accessors operate on whatever
__of_address_to_resource sets into the resource (start, end).

With this special device in place we cannot know if a resource is
assigned with an I/O token or a physical address, unless we forbid
the I/O tokens to be in a specific range.

So this is why we are changing the offsets of all the functions
handling io_range_list (to make sure that a range is forbidden to
the tokens and is available to the physical addresses).

We have chosen this forbidden range to be [0, PCIBIOS_MIN_IO)
because this is the maximum physical I/O range that a non PCI device
can operate on and because we believe this does not impose much
restriction on the available I/O token range; that now is 
[PCIBIOS_MIN_IO, IO_SPACE_LIMIT].
So we believe that the chosen forbidden range can accommodate
any special ISA bus device with no much constraint on the rest
of I/O tokens...

> 
> > > Your current version has
> > >
> > >         if (arm64_extio_ops->pfout)                             \
> > >                 arm64_extio_ops->pfout(arm64_extio_ops->devpara,\
> > >                        addr, value, sizeof(type));             \
> > >
> > > Instead, just subtract the start of the range from the logical
> > > port number to transform it back into a bus-local port number:
> >
> > These accessors do not operate on IO tokens:
> >
> > If (arm64_extio_ops->start > addr || arm64_extio_ops->end < addr)
> > addr is not going to be an I/O token; in fact patch 2/3 imposes that
> > the I/O tokens will start at PCIBIOS_MIN_IO. So from 0 to
> PCIBIOS_MIN_IO
> > we have free physical addresses that the accessors can operate on.
> 
> Ah, I missed that part. I'd rather not use PCIBIOS_MIN_IO to refer to
> the logical I/O tokens, the purpose of that macro is really meant
> for allocating PCI I/O port numbers within the address space of
> one bus.

As I mentioned above, special devices operate on CPU addresses directly,
not I/O tokens. For them there is no way to distinguish....

> 
> Note that it's equally likely that whichever next platform needs
> non-mapped I/O access like this actually needs them for PCI I/O space,
> and that will use it on addresses registered to a PCI host bridge.

Ok so here you are talking about a platform that has got an I/O range
under the PCI host controller, right?
And this I/O range cannot be directly memory mapped but needs special
redirections for the I/O tokens, right?

In this scenario registering the I/O ranges with the forbidden range
implemented by the current patch would still allow to redirect I/O
tokens as long as arm64_extio_ops->start >= PCIBIOS_MIN_IO

So effectively the special PCI host controller
1) knows the physical range that needs special redirection
2) register such range
3) uses pci_pio_to_address() to retrieve the IO tokens for the
   special accessors
4) sets arm64_extio_ops->start/end to the IO tokens retrieved in 3)

So to be honest I think this patch can fit well both with
special PCI controllers that need I/O tokens redirection and with
special non-PCI controllers that need non-PCI I/O physical
address redirection...

Thanks (and sorry for the long reply but I didn't know how
to make the explanation shorter :) )

Gab

> 
> If we separate the two steps:
> 
> a) assign a range of logical I/O port numbers to a bus
> b) register a set of helpers for redirecting logical I/O
>    port to a helper function
> 
> then I think the code will get cleaner and more flexible.
> It should actually then be able to replace the powerpc
> specific implementation.
> 
> 	Arnd
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 5/5] media: platform: rcar_drif: Add DRIF support
From: Hans Verkuil @ 2016-11-11 13:38 UTC (permalink / raw)
  To: Ramesh Shanmugasundaram, robh+dt, mark.rutland, mchehab,
	sakari.ailus, crope
  Cc: chris.paterson2, laurent.pinchart, geert+renesas, linux-media,
	devicetree, linux-renesas-soc
In-Reply-To: <1478706284-59134-6-git-send-email-ramesh.shanmugasundaram@bp.renesas.com>

On 11/09/2016 04:44 PM, Ramesh Shanmugasundaram wrote:
> This patch adds Digital Radio Interface (DRIF) support to R-Car Gen3 SoCs.
> The driver exposes each instance of DRIF as a V4L2 SDR device. A DRIF
> device represents a channel and each channel can have one or two
> sub-channels respectively depending on the target board.
> 
> DRIF supports only Rx functionality. It receives samples from a RF
> frontend tuner chip it is interfaced with. The combination of DRIF and the
> tuner device, which is registered as a sub-device, determines the receive
> sample rate and format.
> 
> In order to be compliant as a V4L2 SDR device, DRIF needs to bind with
> the tuner device, which can be provided by a third party vendor. DRIF acts
> as a slave device and the tuner device acts as a master transmitting the
> samples. The driver allows asynchronous binding of a tuner device that
> is registered as a v4l2 sub-device. The driver can learn about the tuner
> it is interfaced with based on port endpoint properties of the device in
> device tree. The V4L2 SDR device inherits the controls exposed by the
> tuner device.
> 
> The device can also be configured to use either one or both of the data
> pins at runtime based on the master (tuner) configuration.
> 
> Signed-off-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
> ---
>  .../devicetree/bindings/media/renesas,drif.txt     |  136 ++
>  drivers/media/platform/Kconfig                     |   25 +
>  drivers/media/platform/Makefile                    |    1 +
>  drivers/media/platform/rcar_drif.c                 | 1574 ++++++++++++++++++++
>  4 files changed, 1736 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/renesas,drif.txt
>  create mode 100644 drivers/media/platform/rcar_drif.c
> 
> diff --git a/Documentation/devicetree/bindings/media/renesas,drif.txt b/Documentation/devicetree/bindings/media/renesas,drif.txt
> new file mode 100644
> index 0000000..d65368a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/renesas,drif.txt
> @@ -0,0 +1,136 @@
> +Renesas R-Car Gen3 Digital Radio Interface controller (DRIF)
> +------------------------------------------------------------
> +
> +R-Car Gen3 DRIF is a serial slave device. It interfaces with a master
> +device as shown below
> +
> ++---------------------+                +---------------------+
> +|                     |-----SCK------->|CLK                  |
> +|       Master        |-----SS-------->|SYNC  DRIFn (slave)  |
> +|                     |-----SD0------->|D0                   |
> +|                     |-----SD1------->|D1                   |
> ++---------------------+                +---------------------+
> +
> +Each DRIF channel (drifn) consists of two sub-channels (drifn0 & drifn1).
> +The sub-channels are like two individual channels in itself that share the
> +common CLK & SYNC. Each sub-channel has it's own dedicated resources like
> +irq, dma channels, address space & clock.
> +
> +The device tree model represents the channel and each of it's sub-channel
> +as a separate node. The parent channel ties the sub-channels together with
> +their phandles.
> +
> +Required properties of a sub-channel:
> +-------------------------------------
> +- compatible: "renesas,r8a7795-drif" if DRIF controller is a part of R8A7795 SoC.
> +	      "renesas,rcar-gen3-drif" for a generic R-Car Gen3 compatible device.
> +	      When compatible with the generic version, nodes must list the
> +	      SoC-specific version corresponding to the platform first
> +	      followed by the generic version.
> +- reg: offset and length of that sub-channel.
> +- interrupts: associated with that sub-channel.
> +- clocks: phandle and clock specifier of that sub-channel.
> +- clock-names: clock input name string: "fck".
> +- dmas: phandles to the DMA channel of that sub-channel.
> +- dma-names: names of the DMA channel: "rx".
> +
> +Optional properties of a sub-channel:
> +-------------------------------------
> +- power-domains: phandle to the respective power domain.
> +
> +Required properties of a channel:
> +---------------------------------
> +- pinctrl-0: pin control group to be used for this channel.
> +- pinctrl-names: must be "default".
> +- sub-channels : phandles to the two sub-channels.
> +
> +Optional properties of a channel:
> +---------------------------------
> +- port: child port node of a channel that defines the local and remote
> +        endpoints. The remote endpoint is assumed to be a tuner subdevice
> +	endpoint.
> +- renesas,syncmd       : sync mode
> +			 0 (Frame start sync pulse mode. 1-bit width pulse
> +			    indicates start of a frame)
> +			 1 (L/R sync or I2S mode) (default)
> +- renesas,lsb-first    : empty property indicates lsb bit is received first.
> +			 When not defined msb bit is received first (default)
> +- renesas,syncac-pol-high  : empty property indicates sync signal polarity.
> +			 When defined, active high or high->low sync signal.
> +			 When not defined, active low or low->high sync signal
> +			 (default)
> +- renesas,dtdl         : delay between sync signal and start of reception.
> +			 Must contain one of the following values:
> +			 0   (no bit delay)
> +			 50  (0.5-clock-cycle delay)
> +			 100 (1-clock-cycle delay) (default)
> +			 150 (1.5-clock-cycle delay)
> +			 200 (2-clock-cycle delay)
> +- renesas,syncdl       : delay between end of reception and sync signal edge.
> +			 Must contain one of the following values:
> +			 0   (no bit delay) (default)
> +			 50  (0.5-clock-cycle delay)
> +			 100 (1-clock-cycle delay)
> +			 150 (1.5-clock-cycle delay)
> +			 200 (2-clock-cycle delay)
> +			 300 (3-clock-cycle delay)
> +
> +Example
> +--------
> +
> +SoC common dtsi file
> +
> +		drif00: rif@e6f40000 {
> +			compatible = "renesas,r8a7795-drif",
> +				     "renesas,rcar-gen3-drif";
> +			reg = <0 0xe6f40000 0 0x64>;
> +			interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
> +			clocks = <&cpg CPG_MOD 515>;
> +			clock-names = "fck";
> +			dmas = <&dmac1 0x20>, <&dmac2 0x20>;
> +			dma-names = "rx", "rx";
> +			power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
> +			status = "disabled";
> +		};
> +
> +		drif01: rif@e6f50000 {
> +			compatible = "renesas,r8a7795-drif",
> +				     "renesas,rcar-gen3-drif";
> +			reg = <0 0xe6f50000 0 0x64>;
> +			interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
> +			clocks = <&cpg CPG_MOD 514>;
> +			clock-names = "fck";
> +			dmas = <&dmac1 0x22>, <&dmac2 0x22>;
> +			dma-names = "rx", "rx";
> +			power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
> +			status = "disabled";
> +		};
> +
> +		drif0: rif@0 {
> +			compatible = "renesas,r8a7795-drif",
> +				     "renesas,rcar-gen3-drif";
> +			sub-channels = <&drif00>, <&drif01>;
> +			status = "disabled";
> +		};
> +
> +Board specific dts file
> +
> +&drif00 {
> +	status = "okay";
> +};
> +
> +&drif01 {
> +	status = "okay";
> +};
> +
> +&drif0 {
> +	pinctrl-0 = <&drif0_pins>;
> +	pinctrl-names = "default";
> +	renesas,syncac-pol-high;
> +	status = "okay";
> +	port {
> +		drif0_ep: endpoint {
> +		     remote-endpoint = <&tuner_subdev_ep>;
> +		};
> +	};
> +};
> diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> index 754edbf1..0ae83a8 100644
> --- a/drivers/media/platform/Kconfig
> +++ b/drivers/media/platform/Kconfig
> @@ -393,3 +393,28 @@ menuconfig DVB_PLATFORM_DRIVERS
>  if DVB_PLATFORM_DRIVERS
>  source "drivers/media/platform/sti/c8sectpfe/Kconfig"
>  endif #DVB_PLATFORM_DRIVERS
> +
> +menuconfig SDR_PLATFORM_DRIVERS
> +	bool "SDR platform devices"
> +	depends on MEDIA_SDR_SUPPORT
> +	default n
> +	---help---
> +	  Say Y here to enable support for platform-specific SDR Drivers.
> +
> +if SDR_PLATFORM_DRIVERS
> +
> +config VIDEO_RCAR_DRIF
> +	tristate "Renesas Digitial Radio Interface (DRIF)"
> +	depends on VIDEO_V4L2 && HAS_DMA
> +	depends on ARCH_RENESAS
> +	select VIDEOBUF2_VMALLOC
> +	---help---
> +	  Say Y if you want to enable R-Car Gen3 DRIF support. DRIF is Digital
> +	  Radio Interface that interfaces with an RF front end chip. It is a
> +	  receiver of digital data which uses DMA to transfer received data to
> +	  a configured location for an application to use.
> +
> +	  To compile this driver as a module, choose M here; the module
> +	  will be called rcar_drif.
> +
> +endif # SDR_PLATFORM_DRIVERS
> diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> index f842933..49ce238 100644
> --- a/drivers/media/platform/Makefile
> +++ b/drivers/media/platform/Makefile
> @@ -49,6 +49,7 @@ obj-$(CONFIG_SOC_CAMERA)		+= soc_camera/
>  
>  obj-$(CONFIG_VIDEO_RENESAS_FCP) 	+= rcar-fcp.o
>  obj-$(CONFIG_VIDEO_RENESAS_JPU) 	+= rcar_jpu.o
> +obj-$(CONFIG_VIDEO_RCAR_DRIF)		+= rcar_drif.o
>  obj-$(CONFIG_VIDEO_RENESAS_VSP1)	+= vsp1/
>  
>  obj-y	+= omap/
> diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c
> new file mode 100644
> index 0000000..34dc282
> --- /dev/null
> +++ b/drivers/media/platform/rcar_drif.c
> @@ -0,0 +1,1574 @@

<snip>

+#define for_each_rcar_drif_subdev(sd, tmp, ch)				\
+	list_for_each_entry_safe(sd, tmp, &ch->v4l2_dev.subdevs, list)
+

Please don't use this. media/v4l2-device.h has a bunch of similar functions
for this. Use those instead.

<snip>

> +static int rcar_drif_querycap(struct file *file, void *fh,
> +			      struct v4l2_capability *cap)
> +{
> +	struct rcar_drif_chan *ch = video_drvdata(file);
> +
> +	strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
> +	strlcpy(cap->card, ch->vdev.name, sizeof(cap->card));
> +	cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER |
> +				   V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
> +	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;

Set device_caps in struct video_device and drop it here.

The core will fill in cap->device_caps and cap->capabilities for you.

> +	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
> +		 ch->vdev.name);
> +	return 0;
> +}
> +
> +static int rcar_drif_set_default_format(struct rcar_drif_chan *ch)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < NUM_FORMATS; i++) {
> +		/* Find any matching fmt and set it as default */
> +		if (ch->num_hw_schans == formats[i].num_schans) {
> +			ch->fmt_idx = i;
> +			ch->cur_schans_mask = ch->hw_schans_mask;
> +			ch->num_cur_schans = ch->num_hw_schans;
> +			dev_dbg(ch->dev, "default fmt[%u]: mask %lu num %u\n",
> +				i, ch->cur_schans_mask, ch->num_cur_schans);
> +			return 0;
> +		}
> +	}
> +	dev_err(ch->dev, "no matching sdr fmt found\n");
> +	return -EINVAL;
> +}
> +
> +static int rcar_drif_enum_fmt_sdr_cap(struct file *file, void *priv,
> +				      struct v4l2_fmtdesc *f)
> +{
> +	if (f->index >= NUM_FORMATS)
> +		return -EINVAL;
> +
> +	strlcpy(f->description, formats[f->index].name, sizeof(f->description));

Drop this. The core fills that in for you.

> +	f->pixelformat = formats[f->index].pixelformat;
> +	return 0;
> +}
> +
> +static int rcar_drif_g_fmt_sdr_cap(struct file *file, void *priv,
> +				   struct v4l2_format *f)
> +{
> +	struct rcar_drif_chan *ch = video_drvdata(file);
> +
> +	f->fmt.sdr.pixelformat = formats[ch->fmt_idx].pixelformat;
> +	f->fmt.sdr.buffersize = formats[ch->fmt_idx].buffersize;
> +	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
> +	return 0;
> +}
> +
> +static int rcar_drif_s_fmt_sdr_cap(struct file *file, void *priv,
> +				   struct v4l2_format *f)
> +{
> +	struct rcar_drif_chan *ch = video_drvdata(file);
> +	struct vb2_queue *q = &ch->vb_queue;
> +	unsigned int i;
> +
> +	if (vb2_is_busy(q))
> +		return -EBUSY;
> +
> +	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
> +	for (i = 0; i < NUM_FORMATS; i++) {
> +		if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
> +			ch->fmt_idx  = i;
> +			f->fmt.sdr.buffersize = formats[i].buffersize;
> +
> +			/*
> +			 * If a format demands one sub-channel only out of two
> +			 * enabled sub-channels then pick the 0th sub-channel
> +			 */
> +			if (formats[i].num_schans < ch->num_hw_schans) {
> +				ch->cur_schans_mask = BIT(0);	/* Enable D0 */
> +				ch->num_cur_schans = formats[i].num_schans;
> +			} else {
> +				ch->cur_schans_mask = ch->hw_schans_mask;
> +				ch->num_cur_schans = ch->num_hw_schans;
> +			}
> +
> +			rdrif_dbg(1, ch, "cur: idx %u mask %lu num %u\n",
> +				  i, ch->cur_schans_mask, ch->num_cur_schans);
> +			return 0;
> +		}
> +	}
> +
> +	if (rcar_drif_set_default_format(ch))
> +		return -EINVAL;
> +
> +	f->fmt.sdr.pixelformat = formats[ch->fmt_idx].pixelformat;
> +	f->fmt.sdr.buffersize = formats[ch->fmt_idx].buffersize;
> +	return 0;
> +}
> +
> +static int rcar_drif_try_fmt_sdr_cap(struct file *file, void *priv,
> +				     struct v4l2_format *f)
> +{
> +	struct rcar_drif_chan *ch = video_drvdata(file);
> +	unsigned int i;
> +
> +	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
> +	for (i = 0; i < NUM_FORMATS; i++) {
> +		if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
> +			f->fmt.sdr.buffersize = formats[i].buffersize;
> +			return 0;
> +		}
> +	}
> +
> +	f->fmt.sdr.pixelformat = formats[ch->fmt_idx].pixelformat;
> +	f->fmt.sdr.buffersize = formats[ch->fmt_idx].buffersize;
> +	return 0;
> +}
> +
> +/* Tuner subdev ioctls */
> +static int rcar_drif_enum_freq_bands(struct file *file, void *priv,
> +				     struct v4l2_frequency_band *band)
> +{
> +	struct rcar_drif_chan *ch = video_drvdata(file);
> +	struct v4l2_subdev *sd, *tmp;
> +	int ret = 0;
> +
> +	for_each_rcar_drif_subdev(sd, tmp, ch) {
> +		ret = v4l2_subdev_call(sd, tuner, enum_freq_bands, band);
> +		if (ret)
> +			break;
> +	}
> +	return ret;
> +}
> +
> +static int rcar_drif_g_frequency(struct file *file, void *priv,
> +				 struct v4l2_frequency *f)
> +{
> +	struct rcar_drif_chan *ch = video_drvdata(file);
> +	struct v4l2_subdev *sd, *tmp;
> +	int ret = 0;
> +
> +	for_each_rcar_drif_subdev(sd, tmp, ch) {
> +		ret = v4l2_subdev_call(sd, tuner, g_frequency, f);
> +		if (ret)
> +			break;
> +	}
> +	return ret;
> +}
> +
> +static int rcar_drif_s_frequency(struct file *file, void *priv,
> +				 const struct v4l2_frequency *f)
> +{
> +	struct rcar_drif_chan *ch = video_drvdata(file);
> +	struct v4l2_subdev *sd, *tmp;
> +	int ret = 0;
> +
> +	for_each_rcar_drif_subdev(sd, tmp, ch) {
> +		ret = v4l2_subdev_call(sd, tuner, s_frequency, f);
> +		if (ret)
> +			break;
> +	}
> +	return ret;
> +}
> +
> +static int rcar_drif_g_tuner(struct file *file, void *priv,
> +			     struct v4l2_tuner *vt)
> +{
> +	struct rcar_drif_chan *ch = video_drvdata(file);
> +	struct v4l2_subdev *sd, *tmp;
> +	int ret = 0;
> +
> +	for_each_rcar_drif_subdev(sd, tmp, ch) {
> +		ret = v4l2_subdev_call(sd, tuner, g_tuner, vt);
> +		if (ret)
> +			break;
> +	}
> +	return ret;
> +}
> +
> +static int rcar_drif_s_tuner(struct file *file, void *priv,
> +			     const struct v4l2_tuner *vt)
> +{
> +	struct rcar_drif_chan *ch = video_drvdata(file);
> +	struct v4l2_subdev *sd, *tmp;
> +	int ret = 0;
> +
> +	for_each_rcar_drif_subdev(sd, tmp, ch) {
> +		ret = v4l2_subdev_call(sd, tuner, s_tuner, vt);
> +		if (ret)
> +			break;
> +	}
> +	return ret;
> +}
> +
> +static const struct v4l2_ioctl_ops rcar_drif_ioctl_ops = {
> +	.vidioc_querycap          = rcar_drif_querycap,
> +
> +	.vidioc_enum_fmt_sdr_cap  = rcar_drif_enum_fmt_sdr_cap,
> +	.vidioc_g_fmt_sdr_cap     = rcar_drif_g_fmt_sdr_cap,
> +	.vidioc_s_fmt_sdr_cap     = rcar_drif_s_fmt_sdr_cap,
> +	.vidioc_try_fmt_sdr_cap   = rcar_drif_try_fmt_sdr_cap,
> +
> +	.vidioc_reqbufs           = vb2_ioctl_reqbufs,
> +	.vidioc_create_bufs       = vb2_ioctl_create_bufs,
> +	.vidioc_prepare_buf       = vb2_ioctl_prepare_buf,
> +	.vidioc_querybuf          = vb2_ioctl_querybuf,
> +	.vidioc_qbuf              = vb2_ioctl_qbuf,
> +	.vidioc_dqbuf             = vb2_ioctl_dqbuf,
> +
> +	.vidioc_streamon          = vb2_ioctl_streamon,
> +	.vidioc_streamoff         = vb2_ioctl_streamoff,
> +
> +	.vidioc_s_frequency       = rcar_drif_s_frequency,
> +	.vidioc_g_frequency       = rcar_drif_g_frequency,
> +	.vidioc_s_tuner		  = rcar_drif_s_tuner,
> +	.vidioc_g_tuner		  = rcar_drif_g_tuner,
> +	.vidioc_enum_freq_bands   = rcar_drif_enum_freq_bands,
> +	.vidioc_subscribe_event   = v4l2_ctrl_subscribe_event,
> +	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
> +	.vidioc_log_status        = v4l2_ctrl_log_status,
> +};
> +
> +static const struct v4l2_file_operations rcar_drif_fops = {
> +	.owner                    = THIS_MODULE,
> +	.open                     = v4l2_fh_open,
> +	.release                  = vb2_fop_release,
> +	.read                     = vb2_fop_read,
> +	.poll                     = vb2_fop_poll,
> +	.mmap                     = vb2_fop_mmap,
> +	.unlocked_ioctl           = video_ioctl2,
> +};
> +
> +static struct video_device rcar_drif_vdev = {
> +	.name                     = "R-Car DRIF",
> +	.release                  = video_device_release_empty,
> +	.fops                     = &rcar_drif_fops,
> +	.ioctl_ops                = &rcar_drif_ioctl_ops,
> +};
> +
> +static int rcar_drif_notify_bound(struct v4l2_async_notifier *notifier,
> +				   struct v4l2_subdev *subdev,
> +				   struct v4l2_async_subdev *asd)
> +{
> +	struct rcar_drif_chan *ch =
> +		container_of(notifier, struct rcar_drif_chan, notifier);
> +
> +	/* Nothing to do at this point */
> +	rdrif_dbg(2, ch, "bound asd: %s\n", asd->match.of.node->name);
> +	return 0;
> +}
> +
> +/* Sub-device registered notification callback */
> +static int rcar_drif_notify_complete(struct v4l2_async_notifier *notifier)
> +{
> +	struct rcar_drif_chan *ch =
> +		container_of(notifier, struct rcar_drif_chan, notifier);
> +	struct v4l2_subdev *sd, *tmp;
> +	int ret;
> +
> +	v4l2_ctrl_handler_init(&ch->ctrl_hdl, 10);
> +	ch->v4l2_dev.ctrl_handler = &ch->ctrl_hdl;
> +
> +	ret = v4l2_device_register_subdev_nodes(&ch->v4l2_dev);
> +	if (ret) {
> +		rdrif_err(ch, "failed register subdev nodes ret %d\n", ret);
> +		return ret;
> +	}
> +
> +	for_each_rcar_drif_subdev(sd, tmp, ch) {
> +		ret = v4l2_ctrl_add_handler(ch->v4l2_dev.ctrl_handler,
> +					    sd->ctrl_handler, NULL);
> +		if (ret) {
> +			rdrif_err(ch, "failed ctrl add hdlr ret %d\n", ret);
> +			return ret;
> +		}
> +	}
> +	rdrif_dbg(2, ch, "notify complete\n");
> +	return 0;
> +}
> +
> +/* Parse sub-devs (tuner) to find a matching device */
> +static int rcar_drif_parse_subdevs(struct device *dev,
> +				   struct v4l2_async_notifier *notifier)
> +{
> +	struct device_node *node = NULL;
> +
> +	notifier->subdevs = devm_kzalloc(dev, sizeof(*notifier->subdevs),
> +					 GFP_KERNEL);
> +	if (!notifier->subdevs)
> +		return -ENOMEM;
> +
> +	node = of_graph_get_next_endpoint(dev->of_node, node);

Do:

	if (!node)
		return 0;

And the remainder can be shifted one tab to the left.

> +	if (node) {
> +		struct rcar_drif_async_subdev *rsd;
> +
> +		rsd = devm_kzalloc(dev, sizeof(*rsd), GFP_KERNEL);
> +		if (!rsd) {
> +			of_node_put(node);
> +			return -ENOMEM;
> +		}
> +
> +		notifier->subdevs[notifier->num_subdevs] = &rsd->asd;
> +		rsd->asd.match.of.node = of_graph_get_remote_port_parent(node);
> +		of_node_put(node);
> +		if (!rsd->asd.match.of.node) {
> +			dev_warn(dev, "bad remote port parent\n");
> +			return -EINVAL;
> +		}
> +
> +		rsd->asd.match_type = V4L2_ASYNC_MATCH_OF;
> +		notifier->num_subdevs++;
> +	}
> +	return 0;
> +}
> +
> +/* SIRMDR1 configuration */
> +static int rcar_drif_validate_syncmd(struct rcar_drif_chan *ch, u32 val)
> +{
> +	if (val > 1) {
> +		dev_err(ch->dev, "invalid syncmd %u using L/R mode\n", val);
> +		return -EINVAL;
> +	}
> +
> +	ch->mdr1 &= ~(3 << 28);	/* Clear current settings */
> +	if (val == 0)
> +		ch->mdr1 |= RCAR_DRIF_SIRMDR1_SYNCMD_FRAME;
> +	else
> +		ch->mdr1 |= RCAR_DRIF_SIRMDR1_SYNCMD_LR;
> +	return 0;
> +}
> +
> +/* Get the dtdl or syncdl bits as in MSIOF */
> +static u32 rcar_drif_get_dtdl_or_syncdl_bits(u32 dtdl_or_syncdl)
> +{
> +	/*
> +	 * DTDL/SYNCDL bit	: dtdl/syncdl
> +	 * b'000		: 0
> +	 * b'001		: 100
> +	 * b'010		: 200
> +	 * b'011 (SYNCDL only)	: 300
> +	 * b'101		: 50
> +	 * b'110		: 150
> +	 */
> +	if (dtdl_or_syncdl % 100)
> +		return dtdl_or_syncdl / 100 + 5;
> +	else

Line can be dropped.

> +		return dtdl_or_syncdl / 100;
> +}
> +
> +static int rcar_drif_validate_dtdl_syncdl(struct rcar_drif_chan *ch)
> +{
> +	struct device_node *np = ch->dev->of_node;
> +	u32 dtdl = 100, syncdl = 0;
> +
> +	ch->mdr1 |= RCAR_DRIF_SIRMDR1_DTDL_1 | RCAR_DRIF_SIRMDR1_SYNCDL_0;
> +	of_property_read_u32(np, "renesas,dtdl", &dtdl);
> +	of_property_read_u32(np, "renesas,syncdl", &syncdl);
> +
> +	/* Sanity checks */
> +	if (dtdl > 200 || syncdl > 300) {
> +		dev_err(ch->dev, "invalid dtdl %u/syncdl %u\n", dtdl, syncdl);
> +		return -EINVAL;
> +	}
> +	if ((dtdl + syncdl) % 100) {
> +		dev_err(ch->dev, "sum of dtdl %u & syncdl %u not OK\n",
> +			dtdl, syncdl);
> +		return -EINVAL;
> +	}
> +	ch->mdr1 &= ~(7 << 20) & ~(7 << 16);	/* Clear current settings */
> +	ch->mdr1 |= rcar_drif_get_dtdl_or_syncdl_bits(dtdl) << 20;
> +	ch->mdr1 |= rcar_drif_get_dtdl_or_syncdl_bits(syncdl) << 16;
> +	return 0;
> +}
> +
> +static int rcar_drif_parse_properties(struct rcar_drif_chan *ch)
> +{
> +	struct device_node *np = ch->dev->of_node;
> +	u32 syncmd;
> +	int ret;
> +
> +	/* Set the defaults and check for overrides */
> +	ch->mdr1 = RCAR_DRIF_SIRMDR1_SYNCMD_LR;
> +	if (!of_property_read_u32(np, "renesas,syncmd", &syncmd)) {
> +		ret = rcar_drif_validate_syncmd(ch, syncmd);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (of_find_property(np, "renesas,lsb-first", NULL))
> +		ch->mdr1 |= RCAR_DRIF_SIRMDR1_LSB_FIRST;
> +	else
> +		ch->mdr1 |= RCAR_DRIF_SIRMDR1_MSB_FIRST;
> +
> +	if (of_find_property(np, "renesas,syncac-pol-high", NULL))
> +		ch->mdr1 |= RCAR_DRIF_SIRMDR1_SYNCAC_POL_HIGH;
> +	else
> +		ch->mdr1 |= RCAR_DRIF_SIRMDR1_SYNCAC_POL_LOW;
> +
> +	return rcar_drif_validate_dtdl_syncdl(ch);
> +}
> +
> +static u32 rcar_drif_enum_sub_channels(struct platform_device *pdev,
> +					struct platform_device *s_pdev[])
> +{
> +	struct device_node *s_np;
> +	u32 hw_schans_mask = 0;
> +	unsigned int i;
> +
> +	for (i = 0; i < RCAR_DRIF_MAX_SUBCHANS; i++) {
> +		s_np = of_parse_phandle(pdev->dev.of_node, "sub-channels", i);
> +		if (s_np && of_device_is_available(s_np)) {
> +			s_pdev[i] = of_find_device_by_node(s_np);
> +			if (s_pdev[i]) {
> +				hw_schans_mask |= BIT(i);
> +				dev_dbg(&s_pdev[i]->dev, "schan%u ok\n", i);
> +			}
> +		}
> +	}
> +	return hw_schans_mask;
> +}
> +
> +static int rcar_drif_probe(struct platform_device *pdev)
> +{
> +	struct platform_device *s_pdev[RCAR_DRIF_MAX_SUBCHANS];
> +	unsigned long hw_schans_mask;
> +	struct rcar_drif_chan *ch;
> +	unsigned int i;
> +	int ret;
> +
> +	/*
> +	 * Sub-channel resources are managed by the parent channel instance.
> +	 * The sub-channel instance helps only in registering with power domain
> +	 * to aid in run-time pm support
> +	 */
> +	if (!of_find_property(pdev->dev.of_node, "sub-channels", NULL))
> +		return 0;
> +
> +	/* Parent channel instance */
> +	hw_schans_mask = rcar_drif_enum_sub_channels(pdev, s_pdev);
> +	if (!hw_schans_mask) {
> +		dev_err(&pdev->dev, "no sub-channels enabled\n");
> +		return -ENODEV;
> +	}
> +
> +
> +	/* Reserve memory for driver structure */
> +	ch = devm_kzalloc(&pdev->dev, sizeof(*ch), GFP_KERNEL);
> +	if (!ch) {
> +		ret = PTR_ERR(ch);
> +		dev_err(&pdev->dev, "failed alloc drif context\n");
> +		return ret;
> +	}
> +	ch->dev = &pdev->dev;
> +
> +	/* Parse device tree optional properties */
> +	ret = rcar_drif_parse_properties(ch);
> +	if (ret)
> +		return ret;
> +
> +	dev_dbg(ch->dev, "parsed mdr1 0x%08x\n", ch->mdr1);
> +
> +	/* Setup enabled sub-channels */
> +	for_each_rcar_drif_subchannel(i, &hw_schans_mask) {
> +		struct clk *clkp;
> +		struct resource	*res;
> +		void __iomem *base;
> +
> +		/* Peripheral clock */
> +		clkp = devm_clk_get(&s_pdev[i]->dev, "fck");
> +		if (IS_ERR(clkp)) {
> +			ret = PTR_ERR(clkp);
> +			dev_err(&s_pdev[i]->dev, "clk get failed (%d)\n", ret);
> +			return ret;
> +		}
> +
> +		/* Register map */
> +		res = platform_get_resource(s_pdev[i], IORESOURCE_MEM, 0);
> +		base = devm_ioremap_resource(&s_pdev[i]->dev, res);
> +		if (IS_ERR(base)) {
> +			ret = PTR_ERR(base);
> +			dev_err(&s_pdev[i]->dev, "ioremap failed (%d)\n", ret);
> +			return ret;
> +		}
> +
> +		/* Reserve memory for enabled sub-channel */
> +		ch->sch[i] = devm_kzalloc(&pdev->dev, sizeof(*ch->sch[i]),
> +					  GFP_KERNEL);
> +		if (!ch->sch[i]) {
> +			ret = PTR_ERR(ch);
> +			dev_err(&s_pdev[i]->dev, "failed alloc sub-channel\n");
> +			return ret;
> +		}
> +		ch->sch[i]->pdev = s_pdev[i];
> +		ch->sch[i]->clkp = clkp;
> +		ch->sch[i]->base = base;
> +		ch->sch[i]->num = i;
> +		ch->sch[i]->start = res->start;
> +		ch->sch[i]->parent = ch;
> +		ch->num_hw_schans++;
> +	}
> +	ch->hw_schans_mask = hw_schans_mask;
> +
> +	/* Validate any supported format for enabled sub-channels */
> +	ret = rcar_drif_set_default_format(ch);
> +	if (ret)
> +		return ret;
> +
> +	/* Set defaults */
> +	ch->num_hwbufs = RCAR_DRIF_DEFAULT_NUM_HWBUFS;
> +	ch->hwbuf_size = RCAR_DRIF_DEFAULT_HWBUF_SIZE;
> +
> +	mutex_init(&ch->v4l2_mutex);
> +	mutex_init(&ch->vb_queue_mutex);
> +	spin_lock_init(&ch->queued_bufs_lock);
> +	INIT_LIST_HEAD(&ch->queued_bufs);
> +
> +	/* Init videobuf2 queue structure */
> +	ch->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
> +	ch->vb_queue.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF;
> +	ch->vb_queue.drv_priv = ch;
> +	ch->vb_queue.buf_struct_size = sizeof(struct rcar_drif_frame_buf);
> +	ch->vb_queue.ops = &rcar_drif_vb2_ops;
> +	ch->vb_queue.mem_ops = &vb2_vmalloc_memops;
> +	ch->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> +
> +	/* Init videobuf2 queue */
> +	ret = vb2_queue_init(&ch->vb_queue);
> +	if (ret) {
> +		dev_err(ch->dev, "could not initialize vb2 queue\n");
> +		return ret;
> +	}
> +
> +	/* Init video_device structure */
> +	ch->vdev = rcar_drif_vdev;

Don't embed video_device, use video_device_alloc instead. A lot of drivers
embed this, but it turns out not to be a good idea. So new drivers should
use video_device_alloc.

> +	ch->vdev.lock = &ch->v4l2_mutex;
> +	ch->vdev.queue = &ch->vb_queue;
> +	ch->vdev.queue->lock = &ch->vb_queue_mutex;
> +	ch->vdev.ctrl_handler = &ch->ctrl_hdl;
> +	video_set_drvdata(&ch->vdev, ch);
> +
> +	/* Register the v4l2_device */
> +	ret = v4l2_device_register(&pdev->dev, &ch->v4l2_dev);
> +	if (ret) {
> +		dev_err(ch->dev, "failed v4l2_device_register. ret %d\n", ret);
> +		return ret;
> +	}
> +
> +	ch->vdev.v4l2_dev = &ch->v4l2_dev;
> +
> +	/*
> +	 * Parse subdevs after v4l2_device_register because if the subdev
> +	 * is already probed, bound and complete will be called immediately
> +	 */
> +	ret = rcar_drif_parse_subdevs(&pdev->dev, &ch->notifier);
> +	if (ret)
> +		goto err_unreg_v4l2;
> +
> +	ch->notifier.bound = rcar_drif_notify_bound;
> +	ch->notifier.complete = rcar_drif_notify_complete;
> +
> +	/* Register notifier */
> +	ret = v4l2_async_notifier_register(&ch->v4l2_dev, &ch->notifier);
> +	if (ret < 0) {
> +		dev_err(ch->dev, "notifier registration failed\n");
> +		goto err_unreg_v4l2;
> +	}
> +
> +	/* Register SDR device */
> +	ret = video_register_device(&ch->vdev, VFL_TYPE_SDR, -1);
> +	if (ret) {
> +		dev_err(ch->dev, "failed video_register_device. ret %d\n", ret);
> +		goto err_unreg_notif;
> +	}
> +
> +	platform_set_drvdata(pdev, ch);
> +	dev_notice(ch->dev, "probed\n");
> +	return 0;
> +
> +err_unreg_notif:
> +	v4l2_async_notifier_unregister(&ch->notifier);
> +err_unreg_v4l2:
> +	v4l2_device_unregister(&ch->v4l2_dev);
> +	return ret;
> +}
> +
> +static int rcar_drif_remove(struct platform_device *pdev)
> +{
> +	struct rcar_drif_chan *ch = platform_get_drvdata(pdev);
> +
> +	if (!ch)
> +		return 0;
> +
> +	/* Parent channel instance */
> +	ch = platform_get_drvdata(pdev);
> +	v4l2_ctrl_handler_free(ch->v4l2_dev.ctrl_handler);
> +	v4l2_async_notifier_unregister(&ch->notifier);
> +	v4l2_device_unregister(&ch->v4l2_dev);
> +	video_unregister_device(&ch->vdev);
> +	dev_notice(ch->dev, "removed\n");
> +	return 0;
> +}
> +
> +static int __maybe_unused rcar_drif_suspend(struct device *dev)
> +{
> +	return 0;
> +}
> +
> +static int __maybe_unused rcar_drif_resume(struct device *dev)
> +{
> +	return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(rcar_drif_pm_ops, rcar_drif_suspend,
> +			 rcar_drif_resume);
> +
> +static const struct of_device_id rcar_drif_of_table[] = {
> +	{ .compatible = "renesas,rcar-gen3-drif" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, rcar_drif_of_table);
> +
> +#define RCAR_DRIF_DRV_NAME "rcar_drif"
> +static struct platform_driver rcar_drif_driver = {
> +	.driver = {
> +		.name = RCAR_DRIF_DRV_NAME,
> +		.of_match_table = of_match_ptr(rcar_drif_of_table),
> +		.pm = &rcar_drif_pm_ops,
> +		},
> +	.probe = rcar_drif_probe,
> +	.remove = rcar_drif_remove,
> +};
> +
> +module_platform_driver(rcar_drif_driver);
> +
> +MODULE_DESCRIPTION("Renesas R-Car Gen3 DRIF driver");
> +MODULE_ALIAS("platform:" RCAR_DRIF_DRV_NAME);
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>");
> 

Regards,

	Hans

^ permalink raw reply

* Re: [PATCH v5 6/8] Documentation: bindings: add compatible specific to legacy SCPI protocol
From: Rob Herring @ 2016-11-11 13:34 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: Olof Johansson, Neil Armstrong,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <ed58424e-e538-227a-37b5-b35fbe4f96ba-5wv7dgnIgG8@public.gmane.org>

On Fri, Nov 11, 2016 at 1:48 AM, Sudeep Holla <sudeep.holla-5wv7dgnIgG8@public.gmane.org> wrote:
> On 10/11/16 19:03, Olof Johansson wrote:
>> On Thu, Nov 10, 2016 at 6:34 AM, Sudeep Holla <sudeep.holla-5wv7dgnIgG8@public.gmane.org>
>> wrote:

[...]

>>> E.g. Amlogic follows most of the legacy protocol though it deviates in
>>> couple of things which we can handle with platform specific compatible
>>> (in the following patch in the series). When another user(Rockchip ?)
>>> make use of this legacy protocol, we can start using those platform
>>> specific compatible for deviations only.
>>>
>>> Is that not acceptable ?
>>
>>
>> If there's no shared legacy feature set, then it's probably less
>> useful to have a shared less precise compatible value.
>>
>
> There is and will be some shared feature set for sure. At the least the
> standard command set will be shared.
>
>> What the main point I was trying to get across was that we shouldn't
>> expand the generic binding with per-vendor compatible fields, instead
>> we should have those as extensions on the side.
>>
>
> Yes I get the point. We will have per-vendor compatibles for handle the
> deviations but generic one to handle the shared set.
>
>> I'm also a little apprehensive of using "legacy", it goes in the same
>> bucket as "misc". At some point 1.0 will be legacy too, etc.
>>
>
> True and I agree, how about "arm,scpi-pre-1.0" instead ?

That's still meaningless. Convince me that multiple implementations
are identical, then we can have a common property. For example, how
many releases did ARM make before 1.0.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 3/5] media: Add new SDR formats SC16, SC18 & SC20
From: Hans Verkuil @ 2016-11-11 13:24 UTC (permalink / raw)
  To: Ramesh Shanmugasundaram, robh+dt, mark.rutland, mchehab,
	sakari.ailus, crope
  Cc: chris.paterson2, laurent.pinchart, geert+renesas, linux-media,
	devicetree, linux-renesas-soc
In-Reply-To: <1478706284-59134-4-git-send-email-ramesh.shanmugasundaram@bp.renesas.com>

On 11/09/2016 04:44 PM, Ramesh Shanmugasundaram wrote:
> This patch adds support for the three new SDR formats. These formats
> were prefixed with "sliced" indicating I data constitutes the top half and
> Q data constitutes the bottom half of the received buffer.

The standard terminology for video formats is "planar". I am leaning towards
using that here as well.

Any opinions on this?

	Hans

> 
> V4L2_SDR_FMT_SCU16BE - 14-bit complex (I & Q) unsigned big-endian sample
> inside 16-bit. V4L2 FourCC: SC16
> 
> V4L2_SDR_FMT_SCU18BE - 16-bit complex (I & Q) unsigned big-endian sample
> inside 18-bit. V4L2 FourCC: SC18
> 
> V4L2_SDR_FMT_SCU20BE - 18-bit complex (I & Q) unsigned big-endian sample
> inside 20-bit. V4L2 FourCC: SC20
> 
> Signed-off-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
> ---
>  drivers/media/v4l2-core/v4l2-ioctl.c | 3 +++
>  include/uapi/linux/videodev2.h       | 3 +++
>  2 files changed, 6 insertions(+)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> index 181381d..d36b386 100644
> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> @@ -1207,6 +1207,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
>  	case V4L2_SDR_FMT_CS8:		descr = "Complex S8"; break;
>  	case V4L2_SDR_FMT_CS14LE:	descr = "Complex S14LE"; break;
>  	case V4L2_SDR_FMT_RU12LE:	descr = "Real U12LE"; break;
> +	case V4L2_SDR_FMT_SCU16BE:	descr = "Sliced Complex U16BE"; break;
> +	case V4L2_SDR_FMT_SCU18BE:	descr = "Sliced Complex U18BE"; break;
> +	case V4L2_SDR_FMT_SCU20BE:	descr = "Sliced Complex U20BE"; break;
>  	case V4L2_TCH_FMT_DELTA_TD16:	descr = "16-bit signed deltas"; break;
>  	case V4L2_TCH_FMT_DELTA_TD08:	descr = "8-bit signed deltas"; break;
>  	case V4L2_TCH_FMT_TU16:		descr = "16-bit unsigned touch data"; break;
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 4364ce6..34a9c30 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -666,6 +666,9 @@ struct v4l2_pix_format {
>  #define V4L2_SDR_FMT_CS8          v4l2_fourcc('C', 'S', '0', '8') /* complex s8 */
>  #define V4L2_SDR_FMT_CS14LE       v4l2_fourcc('C', 'S', '1', '4') /* complex s14le */
>  #define V4L2_SDR_FMT_RU12LE       v4l2_fourcc('R', 'U', '1', '2') /* real u12le */
> +#define V4L2_SDR_FMT_SCU16BE	  v4l2_fourcc('S', 'C', '1', '6') /* sliced complex u16be */
> +#define V4L2_SDR_FMT_SCU18BE	  v4l2_fourcc('S', 'C', '1', '8') /* sliced complex u18be */
> +#define V4L2_SDR_FMT_SCU20BE	  v4l2_fourcc('S', 'C', '2', '0') /* sliced complex u20be */
>  
>  /* Touch formats - used for Touch devices */
>  #define V4L2_TCH_FMT_DELTA_TD16	v4l2_fourcc('T', 'D', '1', '6') /* 16-bit signed deltas */
> 

^ permalink raw reply

* Re: [PATCH 2/5] media: i2c: max2175: Add MAX2175 support
From: Hans Verkuil @ 2016-11-11 13:21 UTC (permalink / raw)
  To: Ramesh Shanmugasundaram, robh+dt, mark.rutland, mchehab,
	sakari.ailus, crope
  Cc: chris.paterson2, laurent.pinchart, geert+renesas, linux-media,
	devicetree, linux-renesas-soc
In-Reply-To: <1478706284-59134-3-git-send-email-ramesh.shanmugasundaram@bp.renesas.com>

Hi Ramesh,

A quick review:

On 11/09/2016 04:44 PM, Ramesh Shanmugasundaram wrote:
> This patch adds driver support for MAX2175 chip. This is Maxim
> Integrated's RF to Bits tuner front end chip designed for software-defined
> radio solutions. This driver exposes the tuner as a sub-device instance
> with standard and custom controls to configure the device.
> 
> Signed-off-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
> ---
>  .../devicetree/bindings/media/i2c/max2175.txt      |   61 +
>  drivers/media/i2c/Kconfig                          |    4 +
>  drivers/media/i2c/Makefile                         |    2 +
>  drivers/media/i2c/max2175/Kconfig                  |    8 +
>  drivers/media/i2c/max2175/Makefile                 |    4 +
>  drivers/media/i2c/max2175/max2175.c                | 1558 ++++++++++++++++++++
>  drivers/media/i2c/max2175/max2175.h                |  108 ++
>  7 files changed, 1745 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/i2c/max2175.txt
>  create mode 100644 drivers/media/i2c/max2175/Kconfig
>  create mode 100644 drivers/media/i2c/max2175/Makefile
>  create mode 100644 drivers/media/i2c/max2175/max2175.c
>  create mode 100644 drivers/media/i2c/max2175/max2175.h
> 

<snip>

> diff --git a/drivers/media/i2c/max2175/max2175.c b/drivers/media/i2c/max2175/max2175.c
> new file mode 100644
> index 0000000..ec45b52
> --- /dev/null
> +++ b/drivers/media/i2c/max2175/max2175.c
> @@ -0,0 +1,1558 @@

<snip>

> +/* Read/Write bit(s) on top of regmap */
> +static int max2175_read(struct max2175 *ctx, u8 idx, u8 *val)
> +{
> +	u32 regval;
> +	int ret = regmap_read(ctx->regmap, idx, &regval);
> +
> +	if (ret)
> +		v4l2_err(ctx->client, "read ret(%d): idx 0x%02x\n", ret, idx);
> +
> +	*val = regval;

Does regmap_read initialize regval even if it returns an error? If not,
then I would initialize regval to 0 to prevent *val being uninitialized.

> +	return ret;
> +}
> +
> +static int max2175_write(struct max2175 *ctx, u8 idx, u8 val)
> +{
> +	int ret = regmap_write(ctx->regmap, idx, val);
> +
> +	if (ret)
> +		v4l2_err(ctx->client, "write ret(%d): idx 0x%02x val 0x%02x\n",
> +			 ret, idx, val);
> +	return ret;
> +}
> +
> +static u8 max2175_read_bits(struct max2175 *ctx, u8 idx, u8 msb, u8 lsb)
> +{
> +	u8 val;
> +
> +	if (max2175_read(ctx, idx, &val))
> +		return 0;
> +
> +	return max2175_get_bitval(val, msb, lsb);
> +}
> +
> +static bool max2175_read_bit(struct max2175 *ctx, u8 idx, u8 bit)
> +{
> +	return !!max2175_read_bits(ctx, idx, bit, bit);
> +}
> +
> +static int max2175_write_bits(struct max2175 *ctx, u8 idx,
> +			     u8 msb, u8 lsb, u8 newval)
> +{
> +	int ret = regmap_update_bits(ctx->regmap, idx, GENMASK(msb, lsb),
> +				     newval << lsb);
> +
> +	if (ret)
> +		v4l2_err(ctx->client, "wbits ret(%d): idx 0x%02x\n", ret, idx);
> +
> +	return ret;
> +}
> +
> +static int max2175_write_bit(struct max2175 *ctx, u8 idx, u8 bit, u8 newval)
> +{
> +	return max2175_write_bits(ctx, idx, bit, bit, newval);
> +}
> +
> +/* Checks expected pattern every msec until timeout */
> +static int max2175_poll_timeout(struct max2175 *ctx, u8 idx, u8 msb, u8 lsb,
> +				u8 exp_bitval, u32 timeout_ms)
> +{
> +	unsigned int val;
> +
> +	return regmap_read_poll_timeout(ctx->regmap, idx, val,
> +			(max2175_get_bitval(val, msb, lsb) == exp_bitval),
> +			1000, timeout_ms * 1000);
> +}
> +
> +static int max2175_poll_csm_ready(struct max2175 *ctx)
> +{
> +	int ret;
> +
> +	ret = max2175_poll_timeout(ctx, 69, 1, 1, 0, 50);
> +	if (ret)
> +		v4l2_err(ctx->client, "csm not ready\n");
> +
> +	return ret;
> +}
> +
> +#define MAX2175_IS_BAND_AM(ctx)		\
> +	(max2175_read_bits(ctx, 5, 1, 0) == MAX2175_BAND_AM)
> +
> +#define MAX2175_IS_BAND_VHF(ctx)	\
> +	(max2175_read_bits(ctx, 5, 1, 0) == MAX2175_BAND_VHF)
> +
> +#define MAX2175_IS_FM_MODE(ctx)		\
> +	(max2175_read_bits(ctx, 12, 5, 4) == 0)
> +
> +#define MAX2175_IS_FMHD_MODE(ctx)	\
> +	(max2175_read_bits(ctx, 12, 5, 4) == 1)
> +
> +#define MAX2175_IS_DAB_MODE(ctx)	\
> +	(max2175_read_bits(ctx, 12, 5, 4) == 2)
> +
> +static int max2175_band_from_freq(u32 freq)
> +{
> +	if (freq >= 144000 && freq <= 26100000)
> +		return MAX2175_BAND_AM;
> +	else if (freq >= 65000000 && freq <= 108000000)
> +		return MAX2175_BAND_FM;
> +	else

No need for these 'else' keywords.

> +		return MAX2175_BAND_VHF;
> +}
> +
> +static int max2175_update_i2s_mode(struct max2175 *ctx, u32 rx_mode,
> +				   u32 i2s_mode)
> +{
> +	max2175_write_bits(ctx, 29, 2, 0, i2s_mode);
> +
> +	/* Based on I2S mode value I2S_WORD_CNT values change */
> +	switch (i2s_mode) {
> +	case MAX2175_I2S_MODE3:
> +		max2175_write_bits(ctx, 30, 6, 0, 1);
> +		break;
> +	case MAX2175_I2S_MODE2:
> +	case MAX2175_I2S_MODE4:
> +		max2175_write_bits(ctx, 30, 6, 0, 0);
> +		break;
> +	case MAX2175_I2S_MODE0:
> +		max2175_write_bits(ctx, 30, 6, 0,
> +			ctx->rx_modes[rx_mode].i2s_word_size);
> +		break;
> +	}
> +	mxm_dbg(ctx, "update_i2s_mode %u, rx_mode %u\n", i2s_mode, rx_mode);
> +	return 0;
> +}
> +
> +static void max2175_i2s_enable(struct max2175 *ctx, bool enable)
> +{
> +	if (enable) {
> +		/* Use old setting */
> +		max2175_write_bits(ctx, 104, 3, 0, ctx->i2s_test);
> +	} else {
> +		/* Cache old setting */
> +		ctx->i2s_test = max2175_read_bits(ctx, 104, 3, 0);
> +		max2175_write_bits(ctx, 104, 3, 0, 9);	/* Keep SCK alive */
> +	}
> +	mxm_dbg(ctx, "i2s %sabled: old val %u\n", enable ? "en" : "dis",
> +		ctx->i2s_test);
> +}
> +
> +static void max2175_set_filter_coeffs(struct max2175 *ctx, u8 m_sel,
> +				      u8 bank, const u16 *coeffs)
> +{
> +	unsigned int i;
> +	u8 coeff_addr, upper_address = 24;
> +
> +	mxm_dbg(ctx, "set_filter_coeffs: m_sel %d bank %d\n", m_sel, bank);
> +	max2175_write_bits(ctx, 114, 5, 4, m_sel);
> +
> +	if (m_sel == 2)
> +		upper_address = 12;
> +
> +	for (i = 0; i < upper_address; i++) {
> +		coeff_addr = i + bank * 24;
> +		max2175_write(ctx, 115, coeffs[i] >> 8);
> +		max2175_write(ctx, 116, coeffs[i]);
> +		max2175_write(ctx, 117, coeff_addr | 1 << 7);
> +	}
> +	max2175_write_bit(ctx, 117, 7, 0);
> +}
> +
> +static void max2175_load_fmeu_1p2(struct max2175 *ctx)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(fmeu1p2_map); i++)
> +		max2175_write(ctx, fmeu1p2_map[i].idx, fmeu1p2_map[i].val);
> +
> +	ctx->decim_ratio = 36;
> +
> +	/* Load the Channel Filter Coefficients into channel filter bank #2 */
> +	max2175_set_filter_coeffs(ctx, MAX2175_CH_MSEL, 0, ch_coeff_fmeu);
> +	max2175_set_filter_coeffs(ctx, MAX2175_EQ_MSEL, 0,
> +				  eq_coeff_fmeu1_ra02_m6db);
> +}
> +
> +static void max2175_load_dab_1p2(struct max2175 *ctx)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(dab12_map); i++)
> +		max2175_write(ctx, dab12_map[i].idx, dab12_map[i].val);
> +
> +	ctx->decim_ratio = 1;
> +
> +	/* Load the Channel Filter Coefficients into channel filter bank #2 */
> +	max2175_set_filter_coeffs(ctx, MAX2175_CH_MSEL, 2, ch_coeff_dab1);
> +}
> +
> +static void max2175_load_fmna_1p0(struct max2175 *ctx)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(fmna1p0_map); i++)
> +		max2175_write(ctx, fmna1p0_map[i].idx, fmna1p0_map[i].val);
> +}
> +
> +static void max2175_load_fmna_2p0(struct max2175 *ctx)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(fmna2p0_map); i++)
> +		max2175_write(ctx, fmna2p0_map[i].idx, fmna2p0_map[i].val);
> +}
> +
> +static void max2175_set_bbfilter(struct max2175 *ctx)
> +{
> +	if (MAX2175_IS_BAND_AM(ctx)) {
> +		max2175_write_bits(ctx, 12, 3, 0, ctx->rom_bbf_bw_am);
> +		mxm_dbg(ctx, "set_bbfilter AM: rom %d\n", ctx->rom_bbf_bw_am);
> +	} else if (MAX2175_IS_DAB_MODE(ctx)) {
> +		max2175_write_bits(ctx, 12, 3, 0, ctx->rom_bbf_bw_dab);
> +		mxm_dbg(ctx, "set_bbfilter DAB: rom %d\n", ctx->rom_bbf_bw_dab);
> +	} else {
> +		max2175_write_bits(ctx, 12, 3, 0, ctx->rom_bbf_bw_fm);
> +		mxm_dbg(ctx, "set_bbfilter FM: rom %d\n", ctx->rom_bbf_bw_fm);
> +	}
> +}
> +
> +static bool max2175_set_csm_mode(struct max2175 *ctx,
> +			  enum max2175_csm_mode new_mode)
> +{
> +	int ret = max2175_poll_csm_ready(ctx);
> +
> +	if (ret)
> +		return ret;
> +
> +	max2175_write_bits(ctx, 0, 2, 0, new_mode);
> +	mxm_dbg(ctx, "set csm new mode %d\n", new_mode);
> +
> +	/* Wait for a fixed settle down time depending on new mode */
> +	switch (new_mode) {
> +	case MAX2175_PRESET_TUNE:
> +		usleep_range(51100, 51500);	/* 51.1ms */
> +		break;
> +	/*
> +	 * Other mode switches need different sleep values depending on band &
> +	 * mode
> +	 */
> +	default:
> +		break;
> +	}
> +
> +	return max2175_poll_csm_ready(ctx);
> +}
> +
> +static int max2175_csm_action(struct max2175 *ctx,
> +			      enum max2175_csm_mode action)
> +{
> +	int ret;
> +
> +	mxm_dbg(ctx, "csm_action: %d\n", action);
> +
> +	/* Other actions can be added in future when needed */
> +	ret = max2175_set_csm_mode(ctx, MAX2175_LOAD_TO_BUFFER);
> +	if (ret)
> +		return ret;
> +	return max2175_set_csm_mode(ctx, MAX2175_PRESET_TUNE);
> +}
> +
> +static int max2175_set_lo_freq(struct max2175 *ctx, u64 lo_freq)
> +{
> +	u64 scaled_lo_freq, scaled_npf, scaled_integer, scaled_fraction;
> +	u32 frac_desired, int_desired, lo_mult = 1;
> +	const u32 scale_factor = 1000000U;
> +	u8 loband_bits = 0, vcodiv_bits = 0;
> +	enum max2175_band band;
> +	int ret;
> +
> +	/* Scale to larger number for precision */
> +	scaled_lo_freq = lo_freq * scale_factor * 100;
> +	band = max2175_read_bits(ctx, 5, 1, 0);
> +
> +	mxm_dbg(ctx, "set_lo_freq: scaled lo_freq %llu lo_freq %llu band %d\n",
> +		scaled_lo_freq, lo_freq, band);
> +
> +	switch (band) {
> +	case MAX2175_BAND_AM:
> +		if (max2175_read_bit(ctx, 5, 7) == 0)
> +			lo_mult = 16;
> +		break;
> +	case MAX2175_BAND_FM:
> +		if (lo_freq <= 74700000) {
> +			lo_mult = 16;
> +		} else if (lo_freq > 74700000 && lo_freq <= 110000000) {
> +			loband_bits = 1;
> +		} else {
> +			loband_bits = 1;
> +			vcodiv_bits = 3;
> +		}
> +		lo_mult = 8;
> +		break;
> +	case MAX2175_BAND_VHF:
> +		if (lo_freq <= 210000000) {
> +			loband_bits = 2;
> +			vcodiv_bits = 2;
> +		} else {
> +			loband_bits = 2;
> +			vcodiv_bits = 1;
> +		}
> +		lo_mult = 4;
> +		break;
> +	default:
> +		loband_bits = 3;
> +		vcodiv_bits = 2;
> +		lo_mult = 2;
> +		break;
> +	}
> +
> +	if (band == MAX2175_BAND_L)
> +		scaled_npf = div_u64(div_u64(scaled_lo_freq, ctx->xtal_freq),
> +				     lo_mult);
> +	else
> +		scaled_npf = div_u64(scaled_lo_freq, ctx->xtal_freq) * lo_mult;
> +
> +	scaled_npf = div_u64(scaled_npf, 100);
> +	scaled_integer = div_u64(scaled_npf, scale_factor) * scale_factor;
> +	int_desired = div_u64(scaled_npf, scale_factor);
> +	scaled_fraction = scaled_npf - scaled_integer;
> +	frac_desired = div_u64(scaled_fraction << 20, scale_factor);
> +
> +	/* Check CSM is not busy */
> +	ret = max2175_poll_csm_ready(ctx);
> +	if (ret)
> +		return ret;
> +
> +	mxm_dbg(ctx, "loband %u vcodiv %u lo_mult %u scaled_npf %llu\n",
> +		loband_bits, vcodiv_bits, lo_mult, scaled_npf);
> +	mxm_dbg(ctx, "scaled int %llu frac %llu desired int %u frac %u\n",
> +		scaled_integer, scaled_fraction, int_desired, frac_desired);
> +
> +	/* Write the calculated values to the appropriate registers */
> +	max2175_write(ctx, 1, int_desired);
> +	max2175_write_bits(ctx, 2, 3, 0, (frac_desired >> 16) & 0xf);
> +	max2175_write(ctx, 3, frac_desired >> 8);
> +	max2175_write(ctx, 4, frac_desired);
> +	max2175_write_bits(ctx, 5, 3, 2, loband_bits);
> +	max2175_write_bits(ctx, 6, 7, 6, vcodiv_bits);
> +	return ret;
> +}
> +
> +static int max2175_set_nco_freq(struct max2175 *ctx, s64 nco_freq_desired)
> +{
> +	s64  nco_freq, nco_val_desired;
> +	u64 abs_nco_freq;
> +	const u32 scale_factor = 1000000U;
> +	u32 clock_rate, nco_reg;
> +	int ret;
> +
> +	mxm_dbg(ctx, "set_nco_freq: freq %lld\n", nco_freq_desired);
> +	clock_rate = ctx->xtal_freq / ctx->decim_ratio;
> +	nco_freq = -nco_freq_desired;
> +
> +	if (nco_freq < 0)
> +		abs_nco_freq = -nco_freq;
> +	else
> +		abs_nco_freq = nco_freq;
> +
> +	/* Scale up the values for precision */
> +	if (abs_nco_freq < (clock_rate / 2)) {
> +		nco_val_desired = div_s64(2 * nco_freq * scale_factor,
> +					  clock_rate);
> +	} else {
> +		if (nco_freq < 0)
> +			nco_val_desired =
> +			div_s64(-2 * (clock_rate - abs_nco_freq) * scale_factor,
> +				clock_rate);
> +		else
> +			nco_val_desired =
> +			div_s64(2 * (clock_rate - abs_nco_freq) * scale_factor,
> +				clock_rate);
> +	}
> +
> +	/* Scale down to get the fraction */
> +	if (nco_freq < 0)
> +		nco_reg = 0x200000 + div_s64(nco_val_desired << 20,
> +						  scale_factor);
> +	else
> +		nco_reg = div_s64(nco_val_desired << 20, scale_factor);
> +
> +	/* Check CSM is not busy */
> +	ret = max2175_poll_csm_ready(ctx);
> +	if (ret)
> +		return ret;
> +
> +	mxm_dbg(ctx, "clk %u decim %u abs %llu desired %lld reg %u\n",
> +		clock_rate, ctx->decim_ratio, abs_nco_freq,
> +		nco_val_desired, nco_reg);
> +
> +	/* Write the calculated values to the appropriate registers */
> +	max2175_write_bits(ctx, 7, 4, 0, (nco_reg >> 16) & 0x1f);
> +	max2175_write(ctx, 8, nco_reg >> 8);
> +	max2175_write(ctx, 9, nco_reg);
> +	return ret;
> +}
> +
> +static int max2175_set_rf_freq_non_am_bands(struct max2175 *ctx, u64 freq,
> +					    u32 lo_pos)
> +{
> +	s64 adj_freq;
> +	u64 low_if_freq;
> +	int ret;
> +
> +	mxm_dbg(ctx, "rf_freq: non AM bands\n");
> +
> +	if (MAX2175_IS_FM_MODE(ctx))
> +		low_if_freq = 128000;
> +	else if (MAX2175_IS_FMHD_MODE(ctx))
> +		low_if_freq = 228000;
> +	else
> +		return max2175_set_lo_freq(ctx, freq);
> +
> +	if (MAX2175_IS_BAND_VHF(ctx) == (lo_pos == MAX2175_LO_ABOVE_DESIRED))
> +		adj_freq = freq + low_if_freq;
> +	else
> +		adj_freq = freq - low_if_freq;
> +
> +	ret = max2175_set_lo_freq(ctx, adj_freq);
> +	if (ret)
> +		return ret;
> +
> +	return max2175_set_nco_freq(ctx, low_if_freq);
> +}
> +
> +static int max2175_set_rf_freq(struct max2175 *ctx, u64 freq, u32 lo_pos)
> +{
> +	int ret;
> +
> +	if (MAX2175_IS_BAND_AM(ctx))
> +		ret = max2175_set_nco_freq(ctx, freq);
> +	else
> +		ret = max2175_set_rf_freq_non_am_bands(ctx, freq, lo_pos);
> +
> +	mxm_dbg(ctx, "set_rf_freq: ret %d freq %llu\n", ret, freq);
> +	return ret;
> +}
> +
> +static int max2175_tune_rf_freq(struct max2175 *ctx, u64 freq, u32 hsls)
> +{
> +	int ret;
> +
> +	ret = max2175_set_rf_freq(ctx, freq, hsls);
> +	if (ret)
> +		return ret;
> +
> +	ret = max2175_csm_action(ctx, MAX2175_BUFFER_PLUS_PRESET_TUNE);
> +	if (ret)
> +		return ret;
> +
> +	mxm_dbg(ctx, "tune_rf_freq: old %u new %llu\n", ctx->freq, freq);
> +	ctx->freq = freq;
> +	return ret;
> +}
> +
> +static void max2175_set_hsls(struct max2175 *ctx, u32 lo_pos)
> +{
> +	mxm_dbg(ctx, "set_hsls: lo_pos %u\n", lo_pos);
> +
> +	if ((lo_pos == MAX2175_LO_BELOW_DESIRED) == MAX2175_IS_BAND_VHF(ctx))
> +		max2175_write_bit(ctx, 5, 4, 1);
> +	else
> +		max2175_write_bit(ctx, 5, 4, 0);
> +}
> +
> +static void max2175_set_eu_rx_mode(struct max2175 *ctx, u32 rx_mode)
> +{
> +	switch (rx_mode) {
> +	case MAX2175_EU_FM_1_2:
> +		max2175_load_fmeu_1p2(ctx);
> +		break;
> +
> +	case MAX2175_DAB_1_2:
> +		max2175_load_dab_1p2(ctx);
> +		break;
> +	}
> +	/* Master is the default setting */
> +	if (!ctx->master)
> +		max2175_write_bit(ctx, 30, 7, 1);
> +
> +	/* Cache i2s_test value at this point */
> +	ctx->i2s_test = max2175_read_bits(ctx, 104, 3, 0);
> +}
> +
> +static void max2175_set_na_rx_mode(struct max2175 *ctx, u32 rx_mode)
> +{
> +	switch (rx_mode) {
> +	case MAX2175_NA_FM_1_0:
> +		max2175_load_fmna_1p0(ctx);
> +		break;
> +	case MAX2175_NA_FM_2_0:
> +		max2175_load_fmna_2p0(ctx);
> +		break;
> +	}
> +	/* Master is the default setting */
> +	if (!ctx->master)
> +		max2175_write_bit(ctx, 30, 7, 1);
> +
> +	/* Cache i2s_test value at this point */
> +	ctx->i2s_test = max2175_read_bits(ctx, 104, 3, 0);
> +	ctx->decim_ratio = 27;
> +
> +	/* Load the Channel Filter Coefficients into channel filter bank #2 */
> +	max2175_set_filter_coeffs(ctx, MAX2175_CH_MSEL, 0, ch_coeff_fmna);
> +	max2175_set_filter_coeffs(ctx, MAX2175_EQ_MSEL, 0,
> +				  eq_coeff_fmna1_ra02_m6db);
> +}
> +
> +static int max2175_set_rx_mode(struct max2175 *ctx, u32 rx_mode, u32 hsls)
> +{
> +	mxm_dbg(ctx, "set_rx_mode: %u am_hiz %u\n", rx_mode, ctx->am_hiz);
> +	if (ctx->xtal_freq == MAX2175_EU_XTAL_FREQ)
> +		max2175_set_eu_rx_mode(ctx, rx_mode);
> +	else
> +		max2175_set_na_rx_mode(ctx, rx_mode);
> +
> +	if (ctx->am_hiz) {
> +		mxm_dbg(ctx, "setting AM HiZ related config\n");
> +		max2175_write_bit(ctx, 50, 5, 1);
> +		max2175_write_bit(ctx, 90, 7, 1);
> +		max2175_write_bits(ctx, 73, 1, 0, 2);
> +		max2175_write_bits(ctx, 80, 5, 0, 33);
> +	}
> +
> +	/* Load BB filter trim values saved in ROM */
> +	max2175_set_bbfilter(ctx);
> +
> +	/* Set HSLS */
> +	max2175_set_hsls(ctx, hsls);
> +
> +	ctx->mode_resolved = true;
> +	return 0;
> +}
> +
> +static bool max2175_i2s_rx_mode_valid(struct max2175 *ctx,
> +					 u32 mode, u32 i2s_mode)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(ctx->rx_modes[mode].i2s_modes); i++)
> +		if (ctx->rx_modes[mode].i2s_modes[i] == i2s_mode)
> +			return true;
> +
> +	v4l2_err(ctx->client, "i2s_mode %u not suitable for cur rx mode %u\n",
> +		 i2s_mode, mode);
> +	return false;
> +}
> +
> +static int max2175_rx_mode_from_freq(struct max2175 *ctx, u32 freq, u32 *mode)
> +{
> +	unsigned int i;
> +	int band = max2175_band_from_freq(freq);
> +
> +	/* Pick the first match always */
> +	for (i = 0; i <= ctx->rx_mode->maximum; i++) {
> +		if (ctx->rx_modes[i].band == band) {
> +			*mode = i;
> +			mxm_dbg(ctx, "rx_mode_from_freq: freq %u mode %d\n",
> +				freq, *mode);
> +			return 0;
> +		}
> +	}
> +	return -EINVAL;
> +}
> +
> +static bool max2175_freq_rx_mode_valid(struct max2175 *ctx,
> +					 u32 mode, u32 freq)
> +{
> +	int band = max2175_band_from_freq(freq);
> +
> +	return (ctx->rx_modes[mode].band == band);
> +}
> +
> +static void max2175_load_adc_presets(struct max2175 *ctx)
> +{
> +	unsigned int i, j;
> +
> +	for (i = 0; i < 2; i++)
> +		for (j = 0; j < 23; j++)
> +			max2175_write(ctx, 146 + j + i * 55, adc_presets[i][j]);
> +}
> +
> +static int max2175_init_power_manager(struct max2175 *ctx)
> +{
> +	int ret;
> +
> +	/* Execute on-chip power-up/calibration */
> +	max2175_write_bit(ctx, 99, 2, 0);
> +	usleep_range(1000, 1500);
> +	max2175_write_bit(ctx, 99, 2, 1);
> +
> +	/* Wait for the power manager to finish. */
> +	ret = max2175_poll_timeout(ctx, 69, 7, 7, 1, 50);
> +	if (ret)
> +		v4l2_err(ctx->client, "init pm failed\n");
> +	return ret;
> +}
> +
> +static int max2175_recalibrate_adc(struct max2175 *ctx)
> +{
> +	int ret;
> +
> +	/* ADC Re-calibration */
> +	max2175_write(ctx, 150, 0xff);
> +	max2175_write(ctx, 205, 0xff);
> +	max2175_write(ctx, 147, 0x20);
> +	max2175_write(ctx, 147, 0x00);
> +	max2175_write(ctx, 202, 0x20);
> +	max2175_write(ctx, 202, 0x00);
> +
> +	ret = max2175_poll_timeout(ctx, 69, 4, 3, 3, 50);
> +	if (ret)
> +		v4l2_err(ctx->client, "adc recalibration failed\n");
> +	return ret;
> +}
> +
> +static u8 max2175_read_rom(struct max2175 *ctx, u8 row)
> +{
> +	u8 data;
> +
> +	max2175_write_bit(ctx, 56, 4, 0);
> +	max2175_write_bits(ctx, 56, 3, 0, row);
> +
> +	usleep_range(2000, 2500);
> +	max2175_read(ctx, 58, &data);
> +
> +	max2175_write_bits(ctx, 56, 3, 0, 0);
> +
> +	mxm_dbg(ctx, "read_rom: row %d data 0x%02x\n", row, data);
> +	return data;
> +}
> +
> +static void max2175_load_from_rom(struct max2175 *ctx)
> +{
> +	u8 data = 0;
> +
> +	data = max2175_read_rom(ctx, 0);
> +	ctx->rom_bbf_bw_am = data & 0x0f;
> +	max2175_write_bits(ctx, 81, 3, 0, data >> 4);
> +
> +	data = max2175_read_rom(ctx, 1);
> +	ctx->rom_bbf_bw_fm = data & 0x0f;
> +	ctx->rom_bbf_bw_dab = data >> 4;
> +
> +	data = max2175_read_rom(ctx, 2);
> +	max2175_write_bits(ctx, 82, 4, 0, data & 0x1f);
> +	max2175_write_bits(ctx, 82, 7, 5, data >> 5);
> +
> +	data = max2175_read_rom(ctx, 3);
> +	if (ctx->am_hiz) {
> +		data &= 0x0f;
> +		data |= max2175_read_rom(ctx, 7) & 0x40 >> 2;
> +		if (!data)
> +			data |= 2;
> +	} else {
> +		data = data & 0xf0 >> 4;
> +		data |= max2175_read_rom(ctx, 7) & 0x80 >> 3;
> +		if (!data)
> +			data |= 30;
> +	}
> +	max2175_write_bits(ctx, 80, 5, 0, data + 31);
> +
> +	data = max2175_read_rom(ctx, 6);
> +	max2175_write_bits(ctx, 81, 7, 6, data >> 6);
> +}
> +
> +static void max2175_load_full_fm_eu_1p0(struct max2175 *ctx)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(full_fm_eu_1p0); i++)
> +		max2175_write(ctx, i + 1, full_fm_eu_1p0[i]);
> +
> +	usleep_range(5000, 5500);
> +	ctx->decim_ratio = 36;
> +}
> +
> +static void max2175_load_full_fm_na_1p0(struct max2175 *ctx)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(full_fm_na_1p0); i++)
> +		max2175_write(ctx, i + 1, full_fm_na_1p0[i]);
> +
> +	usleep_range(5000, 5500);
> +	ctx->decim_ratio = 27;
> +}
> +
> +static int max2175_core_init(struct max2175 *ctx, u32 refout_bits)
> +{
> +	int ret;
> +
> +	/* MAX2175 uses 36.864MHz clock for EU & 40.154MHz for NA region */
> +	if (ctx->xtal_freq == MAX2175_EU_XTAL_FREQ)
> +		max2175_load_full_fm_eu_1p0(ctx);
> +	else
> +		max2175_load_full_fm_na_1p0(ctx);
> +
> +	/* The default settings assume master */
> +	if (!ctx->master)
> +		max2175_write_bit(ctx, 30, 7, 1);
> +
> +	mxm_dbg(ctx, "refout_bits %u\n", refout_bits);
> +
> +	/* Set REFOUT */
> +	max2175_write_bits(ctx, 56, 7, 5, refout_bits);
> +
> +	/* ADC Reset */
> +	max2175_write_bit(ctx, 99, 1, 0);
> +	usleep_range(1000, 1500);
> +	max2175_write_bit(ctx, 99, 1, 1);
> +
> +	/* Load ADC preset values */
> +	max2175_load_adc_presets(ctx);
> +
> +	/* Initialize the power management state machine */
> +	ret = max2175_init_power_manager(ctx);
> +	if (ret)
> +		return ret;
> +
> +	/* Recalibrate ADC */
> +	ret = max2175_recalibrate_adc(ctx);
> +	if (ret)
> +		return ret;
> +
> +	/* Load ROM values to appropriate registers */
> +	max2175_load_from_rom(ctx);
> +
> +	if (ctx->xtal_freq == MAX2175_EU_XTAL_FREQ) {
> +		/* Load FIR coefficients into bank 0 */
> +		max2175_set_filter_coeffs(ctx, MAX2175_CH_MSEL, 0,
> +					  ch_coeff_fmeu);
> +		max2175_set_filter_coeffs(ctx, MAX2175_EQ_MSEL, 0,
> +					  eq_coeff_fmeu1_ra02_m6db);
> +	} else {
> +		/* Load FIR coefficients into bank 0 */
> +		max2175_set_filter_coeffs(ctx, MAX2175_CH_MSEL, 0,
> +					  ch_coeff_fmna);
> +		max2175_set_filter_coeffs(ctx, MAX2175_EQ_MSEL, 0,
> +					  eq_coeff_fmna1_ra02_m6db);
> +	}
> +	mxm_dbg(ctx, "core initialized\n");
> +	return 0;
> +}
> +
> +static void max2175_s_ctrl_i2s_mode(struct max2175 *ctx, u32 i2s_mode)
> +{
> +	mxm_dbg(ctx, "s_ctrl_i2s_mode: %u resolved %d\n", i2s_mode,
> +		ctx->mode_resolved);
> +
> +	/*
> +	 * Update i2s mode on device only when mode is resolved & it is valid
> +	 * for the configured mode
> +	 */
> +	if (ctx->mode_resolved &&
> +	    max2175_i2s_rx_mode_valid(ctx, ctx->rx_mode->val, i2s_mode))
> +		max2175_update_i2s_mode(ctx, ctx->rx_mode->val, i2s_mode);
> +}
> +
> +static void max2175_s_ctrl_rx_mode(struct max2175 *ctx, u32 rx_mode)
> +{
> +	/* Load mode. Range check already done */
> +	max2175_set_rx_mode(ctx, rx_mode, ctx->hsls->val);
> +
> +	/* Get current i2s_mode and update if needed for given rx_mode */
> +	if (max2175_i2s_rx_mode_valid(ctx, rx_mode, ctx->i2s_mode->val))
> +		max2175_update_i2s_mode(ctx, rx_mode, ctx->i2s_mode->val);
> +	else
> +		ctx->i2s_mode->val = max2175_read_bits(ctx, 29, 2, 0);
> +
> +	mxm_dbg(ctx, "s_ctrl_rx_mode: %u curr freq %u\n", rx_mode, ctx->freq);
> +
> +	/* Check if current freq valid for mode & update */
> +	if (max2175_freq_rx_mode_valid(ctx, rx_mode, ctx->freq))
> +		max2175_tune_rf_freq(ctx, ctx->freq, ctx->hsls->val);
> +	else
> +		/* Use default freq of mode if current freq is not valid */
> +		max2175_tune_rf_freq(ctx, ctx->rx_modes[rx_mode].freq,
> +				     ctx->hsls->val);
> +}
> +
> +static int max2175_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +	struct max2175 *ctx = max2175_from_ctrl_hdl(ctrl->handler);
> +	int ret = 0;
> +
> +	mxm_dbg(ctx, "s_ctrl: id 0x%x, val %u\n", ctrl->id, ctrl->val);
> +	switch (ctrl->id) {
> +	case V4L2_CID_MAX2175_I2S_ENABLE:
> +		max2175_i2s_enable(ctx, ctrl->val == 1);
> +		break;
> +	case V4L2_CID_MAX2175_I2S_MODE:
> +		max2175_s_ctrl_i2s_mode(ctx, ctrl->val);
> +		break;
> +	case V4L2_CID_MAX2175_HSLS:
> +		max2175_set_hsls(ctx, ctx->hsls->val);
> +		break;
> +	case V4L2_CID_MAX2175_RX_MODE:
> +		max2175_s_ctrl_rx_mode(ctx, ctrl->val);
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int max2175_get_lna_gain(struct max2175 *ctx)
> +{
> +	int gain = 0;
> +	enum max2175_band band = max2175_read_bits(ctx, 5, 1, 0);
> +
> +	switch (band) {
> +	case MAX2175_BAND_AM:
> +		gain = max2175_read_bits(ctx, 51, 3, 1);
> +		break;
> +	case MAX2175_BAND_FM:
> +		gain = max2175_read_bits(ctx, 50, 3, 1);
> +		break;
> +	case MAX2175_BAND_VHF:
> +		gain = max2175_read_bits(ctx, 52, 3, 0);
> +		break;
> +	default:
> +		break;
> +	}
> +	return gain;
> +}
> +
> +static int max2175_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +	struct max2175 *ctx = max2175_from_ctrl_hdl(ctrl->handler);
> +
> +	switch (ctrl->id) {
> +	case V4L2_CID_RF_TUNER_LNA_GAIN:
> +		ctrl->val = max2175_get_lna_gain(ctx);
> +		break;
> +	case V4L2_CID_RF_TUNER_IF_GAIN:
> +		ctrl->val = max2175_read_bits(ctx, 49, 4, 0);
> +		break;
> +	case V4L2_CID_RF_TUNER_PLL_LOCK:
> +		ctrl->val = (max2175_read_bits(ctx, 60, 7, 6) == 3);
> +		break;
> +	}
> +	mxm_dbg(ctx, "g_volatile_ctrl: id 0x%x val %d\n", ctrl->id, ctrl->val);
> +	return 0;
> +};
> +
> +static int max2175_set_freq_and_mode(struct max2175 *ctx, u32 freq)
> +{
> +	u32 rx_mode;
> +	int ret;
> +
> +	/* Get band from frequency */
> +	ret = max2175_rx_mode_from_freq(ctx, freq, &rx_mode);
> +	if (ret)
> +		return ret;
> +
> +	mxm_dbg(ctx, "set_freq_and_mode: freq %u rx_mode %d\n", freq, rx_mode);
> +
> +	/* Load mode */
> +	max2175_set_rx_mode(ctx, rx_mode, ctx->hsls->val);
> +	ctx->rx_mode->val = rx_mode;
> +
> +	/* Get current i2s_mode and update if needed for given rx_mode */
> +	if (max2175_i2s_rx_mode_valid(ctx, rx_mode, ctx->i2s_mode->val))
> +		max2175_update_i2s_mode(ctx, rx_mode, ctx->i2s_mode->val);
> +	else
> +		ctx->i2s_mode->val = max2175_read_bits(ctx, 29, 2, 0);
> +
> +	/* Tune to the new freq given */
> +	return max2175_tune_rf_freq(ctx, freq, ctx->hsls->val);
> +}
> +
> +static int max2175_s_frequency(struct v4l2_subdev *sd,
> +			       const struct v4l2_frequency *vf)
> +{
> +	struct max2175 *ctx = max2175_from_sd(sd);
> +	u32 freq;
> +	int ret = 0;
> +
> +	mxm_dbg(ctx, "s_freq: new %u curr %u, mode_resolved %d\n",
> +		vf->frequency, ctx->freq, ctx->mode_resolved);
> +
> +	if (vf->tuner != 0)
> +		return -EINVAL;
> +
> +	freq = clamp(vf->frequency, ctx->bands_rf->rangelow,
> +		     ctx->bands_rf->rangehigh);
> +
> +	/* Check new freq valid for rx_mode if already resolved */
> +	if (ctx->mode_resolved &&
> +	    max2175_freq_rx_mode_valid(ctx, ctx->rx_mode->val, freq))
> +		ret = max2175_tune_rf_freq(ctx, freq, ctx->hsls->val);
> +	else
> +		/* Find default rx_mode for freq and tune to it */
> +		ret = max2175_set_freq_and_mode(ctx, freq);
> +
> +	mxm_dbg(ctx, "s_freq: ret %d curr %u mode_resolved %d mode %u\n",
> +		ret, ctx->freq, ctx->mode_resolved, ctx->rx_mode->val);
> +	return ret;
> +}
> +
> +static int max2175_g_frequency(struct v4l2_subdev *sd,
> +			       struct v4l2_frequency *vf)
> +{
> +	struct max2175 *ctx = max2175_from_sd(sd);
> +	int ret = 0;
> +
> +	if (vf->tuner != 0)
> +		return -EINVAL;
> +
> +	/* RF freq */
> +	vf->type = V4L2_TUNER_RF;
> +	vf->frequency = ctx->freq;
> +	return ret;
> +}
> +
> +static int max2175_enum_freq_bands(struct v4l2_subdev *sd,
> +			    struct v4l2_frequency_band *band)
> +{
> +	struct max2175 *ctx = max2175_from_sd(sd);
> +
> +	if (band->tuner == 0 && band->index == 0)
> +		*band = *ctx->bands_rf;
> +	else
> +		return -EINVAL;

This is a bit ugly. I would invert the condition and return -EINVAL.
Then assign *band and return 0.

> +
> +	return 0;
> +}
> +
> +static int max2175_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
> +{
> +	struct max2175 *ctx = max2175_from_sd(sd);
> +
> +	if (vt->index > 0)
> +		return -EINVAL;
> +
> +	strlcpy(vt->name, "RF", sizeof(vt->name));
> +	vt->type = V4L2_TUNER_RF;
> +	vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
> +	vt->rangelow = ctx->bands_rf->rangelow;
> +	vt->rangehigh = ctx->bands_rf->rangehigh;
> +	return 0;
> +}
> +
> +static int max2175_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
> +{
> +	/* Check tuner index is valid */
> +	if (vt->index > 0)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static const struct v4l2_subdev_tuner_ops max2175_tuner_ops = {
> +	.s_frequency = max2175_s_frequency,
> +	.g_frequency = max2175_g_frequency,
> +	.enum_freq_bands = max2175_enum_freq_bands,
> +	.g_tuner = max2175_g_tuner,
> +	.s_tuner = max2175_s_tuner,
> +};
> +
> +static const struct v4l2_subdev_ops max2175_ops = {
> +	.tuner = &max2175_tuner_ops,
> +};
> +
> +static const struct v4l2_ctrl_ops max2175_ctrl_ops = {
> +	.s_ctrl = max2175_s_ctrl,
> +	.g_volatile_ctrl = max2175_g_volatile_ctrl,
> +};
> +
> +static const struct v4l2_ctrl_config max2175_i2s_en = {
> +	.ops = &max2175_ctrl_ops,
> +	.id = V4L2_CID_MAX2175_I2S_ENABLE,
> +	.name = "I2S Enable",
> +	.type = V4L2_CTRL_TYPE_BOOLEAN,
> +	.min = 0,
> +	.max = 1,
> +	.step = 1,
> +	.def = 1,
> +};
> +
> +static const char * const max2175_ctrl_i2s_modes[] = {
> +	[MAX2175_I2S_MODE0]	= "i2s mode 0",
> +	[MAX2175_I2S_MODE1]	= "i2s mode 1 (skipped)",
> +	[MAX2175_I2S_MODE2]	= "i2s mode 2",
> +	[MAX2175_I2S_MODE3]	= "i2s mode 3",
> +	[MAX2175_I2S_MODE4]	= "i2s mode 4",
> +};
> +
> +static const struct v4l2_ctrl_config max2175_i2s_mode = {
> +	.ops = &max2175_ctrl_ops,
> +	.id = V4L2_CID_MAX2175_I2S_MODE,
> +	.name = "I2S MODE value",
> +	.type = V4L2_CTRL_TYPE_MENU,
> +	.max = ARRAY_SIZE(max2175_ctrl_i2s_modes) - 1,
> +	.def = 0,
> +	.menu_skip_mask = 0x02,
> +	.qmenu = max2175_ctrl_i2s_modes,
> +};

Is this something that is changed dynamically? It looks more like a
device tree thing (it's not clear what it does, so obviously I
can't be sure).

> +
> +static const struct v4l2_ctrl_config max2175_hsls = {
> +	.ops = &max2175_ctrl_ops,
> +	.id = V4L2_CID_MAX2175_HSLS,
> +	.name = "HSLS above/below desired",
> +	.type = V4L2_CTRL_TYPE_INTEGER,
> +	.min = 0,
> +	.max = 1,
> +	.step = 1,
> +	.def = 1,
> +};
> +
> +static const char * const max2175_ctrl_eu_rx_modes[] = {
> +	[MAX2175_EU_FM_1_2]	= "EU FM 1.2",
> +	[MAX2175_DAB_1_2]	= "DAB 1.2",
> +};
> +
> +static const char * const max2175_ctrl_na_rx_modes[] = {
> +	[MAX2175_NA_FM_1_0]	= "NA FM 1.0",
> +	[MAX2175_NA_FM_2_0]	= "NA FM 2.0",
> +};
> +
> +static const struct v4l2_ctrl_config max2175_eu_rx_mode = {
> +	.ops = &max2175_ctrl_ops,
> +	.id = V4L2_CID_MAX2175_RX_MODE,
> +	.name = "RX MODE",
> +	.type = V4L2_CTRL_TYPE_MENU,
> +	.max = ARRAY_SIZE(max2175_ctrl_eu_rx_modes) - 1,
> +	.def = 0,
> +	.qmenu = max2175_ctrl_eu_rx_modes,
> +};
> +
> +static const struct v4l2_ctrl_config max2175_na_rx_mode = {
> +	.ops = &max2175_ctrl_ops,
> +	.id = V4L2_CID_MAX2175_RX_MODE,
> +	.name = "RX MODE",
> +	.type = V4L2_CTRL_TYPE_MENU,
> +	.max = ARRAY_SIZE(max2175_ctrl_na_rx_modes) - 1,
> +	.def = 0,
> +	.qmenu = max2175_ctrl_na_rx_modes,
> +};

Please document all these controls better. This is part of the public API, so
you need to give more information what this means exactly.

> +
> +static int max2175_refout_load_to_bits(struct i2c_client *client, u32 load,
> +				       u32 *bits)
> +{
> +	if (load >= 0 && load <= 40)
> +		*bits = load / 10;
> +	else if (load >= 60 && load <= 70)
> +		*bits = load / 10 - 1;
> +	else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int max2175_probe(struct i2c_client *client,
> +			const struct i2c_device_id *id)
> +{
> +	struct max2175 *ctx;
> +	struct v4l2_subdev *sd;
> +	struct v4l2_ctrl_handler *hdl;
> +	struct clk *clk;
> +	struct regmap *regmap;
> +	bool master = true, am_hiz = false;
> +	u32 refout_load, refout_bits = 0;	/* REFOUT disabled */
> +	int ret;
> +
> +	/* Parse DT properties */
> +	if (of_find_property(client->dev.of_node, "maxim,slave", NULL))
> +		master = false;
> +
> +	if (of_find_property(client->dev.of_node, "maxim,am-hiz", NULL))
> +		am_hiz = true;
> +
> +	if (!of_property_read_u32(client->dev.of_node, "maxim,refout-load-pF",
> +				  &refout_load)) {
> +		ret = max2175_refout_load_to_bits(client, refout_load,
> +						  &refout_bits);
> +		if (ret) {
> +			dev_err(&client->dev, "invalid refout_load %u\n",
> +				refout_load);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	clk = devm_clk_get(&client->dev, "xtal");
> +	if (IS_ERR(clk)) {
> +		ret = PTR_ERR(clk);
> +		dev_err(&client->dev, "cannot get xtal clock %d\n", ret);
> +		return -ENODEV;
> +	}
> +
> +	regmap = devm_regmap_init_i2c(client, &max2175_regmap_config);
> +	if (IS_ERR(regmap)) {
> +		ret = PTR_ERR(regmap);
> +		dev_err(&client->dev, "regmap init failed %d\n", ret);
> +		return -ENODEV;
> +	}
> +
> +	/* Alloc tuner context */
> +	ctx = devm_kzalloc(&client->dev, sizeof(*ctx), GFP_KERNEL);
> +	if (ctx == NULL)
> +		return -ENOMEM;
> +
> +	sd = &ctx->sd;
> +	ctx->master = master;
> +	ctx->am_hiz = am_hiz;
> +	ctx->mode_resolved = false;
> +	ctx->regmap = regmap;
> +	ctx->xtal_freq = clk_get_rate(clk);
> +	dev_info(&client->dev, "xtal freq %luHz\n", ctx->xtal_freq);
> +
> +	v4l2_i2c_subdev_init(sd, client, &max2175_ops);
> +	ctx->client = client;
> +
> +	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
> +
> +	/* Controls */
> +	hdl = &ctx->ctrl_hdl;
> +	ret = v4l2_ctrl_handler_init(hdl, 7);
> +	if (ret) {
> +		dev_err(&client->dev, "ctrl handler init failed\n");
> +		goto err;
> +	}
> +
> +	ctx->lna_gain = v4l2_ctrl_new_std(hdl, &max2175_ctrl_ops,
> +					  V4L2_CID_RF_TUNER_LNA_GAIN,
> +					  0, 15, 1, 2);
> +	ctx->lna_gain->flags |= (V4L2_CTRL_FLAG_VOLATILE |
> +				 V4L2_CTRL_FLAG_READ_ONLY);
> +	ctx->if_gain = v4l2_ctrl_new_std(hdl, &max2175_ctrl_ops,
> +					 V4L2_CID_RF_TUNER_IF_GAIN,
> +					 0, 31, 1, 0);
> +	ctx->if_gain->flags |= (V4L2_CTRL_FLAG_VOLATILE |
> +				V4L2_CTRL_FLAG_READ_ONLY);
> +	ctx->pll_lock = v4l2_ctrl_new_std(hdl, &max2175_ctrl_ops,
> +					  V4L2_CID_RF_TUNER_PLL_LOCK,
> +					  0, 1, 1, 0);
> +	ctx->pll_lock->flags |= (V4L2_CTRL_FLAG_VOLATILE |
> +				 V4L2_CTRL_FLAG_READ_ONLY);
> +	ctx->i2s_en = v4l2_ctrl_new_custom(hdl, &max2175_i2s_en, NULL);
> +	ctx->i2s_mode = v4l2_ctrl_new_custom(hdl, &max2175_i2s_mode, NULL);
> +	ctx->hsls = v4l2_ctrl_new_custom(hdl, &max2175_hsls, NULL);
> +
> +	if (ctx->xtal_freq == MAX2175_EU_XTAL_FREQ) {
> +		ctx->rx_mode = v4l2_ctrl_new_custom(hdl,
> +						    &max2175_eu_rx_mode, NULL);
> +		ctx->rx_modes = eu_rx_modes;
> +		ctx->bands_rf = &eu_bands_rf;
> +	} else {
> +		ctx->rx_mode = v4l2_ctrl_new_custom(hdl,
> +						    &max2175_na_rx_mode, NULL);
> +		ctx->rx_modes = na_rx_modes;
> +		ctx->bands_rf = &na_bands_rf;
> +	}
> +	ctx->sd.ctrl_handler = &ctx->ctrl_hdl;
> +
> +	/* Set the defaults */
> +	ctx->freq = ctx->bands_rf->rangelow;
> +
> +	/* Register subdev */
> +	ret = v4l2_async_register_subdev(sd);
> +	if (ret) {
> +		dev_err(&client->dev, "register subdev failed\n");
> +		goto err_reg;
> +	}
> +
> +	/* Initialize device */
> +	ret = max2175_core_init(ctx, refout_bits);
> +	if (ret)
> +		goto err_init;
> +
> +	dev_info(&client->dev, "probed\n");
> +	return 0;
> +
> +err_init:
> +	v4l2_async_unregister_subdev(sd);
> +err_reg:
> +	v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
> +err:
> +	return ret;
> +}
> +
> +static int max2175_remove(struct i2c_client *client)
> +{
> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> +	struct max2175 *ctx = max2175_from_sd(sd);
> +
> +	v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
> +	v4l2_async_unregister_subdev(sd);
> +	dev_info(&client->dev, "removed\n");
> +	return 0;
> +}
> +
> +static const struct i2c_device_id max2175_id[] = {
> +	{ DRIVER_NAME, 0},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(i2c, max2175_id);
> +
> +static const struct of_device_id max2175_of_ids[] = {
> +	{ .compatible = "maxim, max2175", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, max2175_of_ids);
> +
> +static struct i2c_driver max2175_driver = {
> +	.driver = {
> +		.name	= DRIVER_NAME,
> +		.of_match_table = max2175_of_ids,
> +	},
> +	.probe		= max2175_probe,
> +	.remove		= max2175_remove,
> +	.id_table	= max2175_id,
> +};
> +
> +module_i2c_driver(max2175_driver);
> +
> +MODULE_DESCRIPTION("Maxim MAX2175 RF to Bits tuner driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>");
> diff --git a/drivers/media/i2c/max2175/max2175.h b/drivers/media/i2c/max2175/max2175.h
> new file mode 100644
> index 0000000..2d858aa
> --- /dev/null
> +++ b/drivers/media/i2c/max2175/max2175.h
> @@ -0,0 +1,108 @@
> +/*
> + * Maxim Integrated MAX2175 RF to Bits tuner driver
> + *
> + * This driver & most of the hard coded values are based on the reference
> + * application delivered by Maxim for this chip.
> + *
> + * Copyright (C) 2016 Maxim Integrated Products
> + * Copyright (C) 2016 Renesas Electronics Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __MAX2175_H__
> +#define __MAX2175_H__
> +
> +#define MAX2175_EU_XTAL_FREQ	36864000	/* In Hz */
> +#define MAX2175_NA_XTAL_FREQ	40186125	/* In Hz */
> +
> +enum max2175_region {
> +	MAX2175_REGION_EU = 0,	/* Europe */
> +	MAX2175_REGION_NA,	/* North America */
> +};
> +
> +
> +enum max2175_band {
> +	MAX2175_BAND_AM = 0,
> +	MAX2175_BAND_FM,
> +	MAX2175_BAND_VHF,
> +	MAX2175_BAND_L,
> +};
> +
> +enum max2175_eu_mode {
> +	/* EU modes */
> +	MAX2175_EU_FM_1_2 = 0,
> +	MAX2175_DAB_1_2,
> +
> +	/* Other possible modes to add in future
> +	 * MAX2175_DAB_1_0,
> +	 * MAX2175_DAB_1_3,
> +	 * MAX2175_EU_FM_2_2,
> +	 * MAX2175_EU_FMHD_4_0,
> +	 * MAX2175_EU_AM_1_0,
> +	 * MAX2175_EU_AM_2_2,
> +	 */
> +};
> +
> +enum max2175_na_mode {
> +	/* NA modes */
> +	MAX2175_NA_FM_1_0 = 0,
> +	MAX2175_NA_FM_2_0,
> +
> +	/* Other possible modes to add in future
> +	 * MAX2175_NA_FMHD_1_0,
> +	 * MAX2175_NA_FMHD_1_2,
> +	 * MAX2175_NA_AM_1_0,
> +	 * MAX2175_NA_AM_1_2,
> +	 */
> +};
> +
> +/* Supported I2S modes */
> +enum {
> +	MAX2175_I2S_MODE0 = 0,
> +	MAX2175_I2S_MODE1,
> +	MAX2175_I2S_MODE2,
> +	MAX2175_I2S_MODE3,
> +	MAX2175_I2S_MODE4,
> +};
> +
> +/* Coefficient table groups */
> +enum {
> +	MAX2175_CH_MSEL = 0,
> +	MAX2175_EQ_MSEL,
> +	MAX2175_AA_MSEL,
> +};
> +
> +/* HSLS LO injection polarity */
> +enum {
> +	MAX2175_LO_BELOW_DESIRED = 0,
> +	MAX2175_LO_ABOVE_DESIRED,
> +};
> +
> +/* Channel FSM modes */
> +enum max2175_csm_mode {
> +	MAX2175_LOAD_TO_BUFFER = 0,
> +	MAX2175_PRESET_TUNE,
> +	MAX2175_SEARCH,
> +	MAX2175_AF_UPDATE,
> +	MAX2175_JUMP_FAST_TUNE,
> +	MAX2175_CHECK,
> +	MAX2175_LOAD_AND_SWAP,
> +	MAX2175_END,
> +	MAX2175_BUFFER_PLUS_PRESET_TUNE,
> +	MAX2175_BUFFER_PLUS_SEARCH,
> +	MAX2175_BUFFER_PLUS_AF_UPDATE,
> +	MAX2175_BUFFER_PLUS_JUMP_FAST_TUNE,
> +	MAX2175_BUFFER_PLUS_CHECK,
> +	MAX2175_BUFFER_PLUS_LOAD_AND_SWAP,
> +	MAX2175_NO_ACTION
> +};
> +
> +#endif /* __MAX2175_H__ */
> 

Regards,

	Hans

^ permalink raw reply

* Re: [PATCH v2 2/4] dt-bindings: Add TI SCI PM Domains
From: Ulf Hansson @ 2016-11-11 12:34 UTC (permalink / raw)
  To: Dave Gerlach, Rob Herring
  Cc: Nishanth Menon, devicetree@vger.kernel.org, Santosh Shilimkar,
	linux-pm@vger.kernel.org, Kevin Hilman, Sudeep Holla,
	Rafael J . Wysocki, linux-kernel@vger.kernel.org, Jon Hunter,
	Tero Kristo, Russell King, Keerthy,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <90e91588-d2fc-19be-5a28-63c801a8d061@ti.com>

On 10 November 2016 at 20:56, Dave Gerlach <d-gerlach@ti.com> wrote:
> Rob, Ulf, Jon,
>
> On 10/27/2016 08:15 AM, Dave Gerlach wrote:
>>
>> +Jon
>> On 10/26/2016 04:59 PM, Rob Herring wrote:
>>>
>>> On Mon, Oct 24, 2016 at 12:00 PM, Kevin Hilman <khilman@baylibre.com>
>>> wrote:
>>>>
>>>> Dave Gerlach <d-gerlach@ti.com> writes:
>>>>
>>>>> Hi,
>>>>> On 10/21/2016 01:48 PM, Kevin Hilman wrote:
>>>>>>
>>>>>> Dave Gerlach <d-gerlach@ti.com> writes:
>>>>>>
>>>>>>> Add a generic power domain implementation, TI SCI PM Domains, that
>>>>>>> will hook into the genpd framework and allow the TI SCI protocol to
>>>>>>> control device power states.
>>>>>>>
>>>>>>> Also, provide macros representing each device index as understood
>>>>>>> by TI SCI to be used in the device node power-domain references.
>>>>>>> These are identifiers for the K2G devices managed by the PMMC.
>>>>>>>
>>>>>>> Signed-off-by: Nishanth Menon <nm@ti.com>
>>>>>>> Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
>>>>>>> ---
>>>>>>>  .../devicetree/bindings/soc/ti/sci-pm-domain.txt   | 54
>>>>>>> +++++++++++++
>>>>>>>  MAINTAINERS                                        |  2 +
>>>>>>>  include/dt-bindings/genpd/k2g.h                    | 90
>>>>>>> ++++++++++++++++++++++
>>>>>>>  3 files changed, 146 insertions(+)
>>>>>>>  create mode 100644
>>>>>>> Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>>>>>>>  create mode 100644 include/dt-bindings/genpd/k2g.h
>>>>>>>
>>>>>>> diff --git
>>>>>>> a/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>>>>>>> b/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>>>>>>> new file mode 100644
>>>>>>> index 000000000000..32f38a349656
>>>>>>> --- /dev/null
>>>>>>> +++ b/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>>>>>>> @@ -0,0 +1,54 @@
>>>>>>> +Texas Instruments TI-SCI Generic Power Domain
>>>>>>> +---------------------------------------------
>>>>>>> +
>>>>>>> +Some TI SoCs contain a system controller (like the PMMC, etc...)
>>>>>>> that is
>>>>>>> +responsible for controlling the state of the IPs that are present.
>>>>>>> +Communication between the host processor running an OS and the
>>>>>>> system
>>>>>>> +controller happens through a protocol known as TI-SCI [1]. This pm
>>>>>>> domain
>>>>>>> +implementation plugs into the generic pm domain framework and makes
>>>>>>> use of
>>>>>>> +the TI SCI protocol power on and off each device when needed.
>>>>>>> +
>>>>>>> +[1] Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
>>>>>>> +
>>>>>>> +PM Domain Node
>>>>>>> +==============
>>>>>>> +The PM domain node represents the global PM domain managed by the
>>>>>>> PMMC,
>>>>>>> +which in this case is the single implementation as documented by the
>>>>>>> generic
>>>>>>> +PM domain bindings in
>>>>>>> Documentation/devicetree/bindings/power/power_domain.txt.
>>>>>>> +
>>>>>>> +Required Properties:
>>>>>>> +--------------------
>>>>>>> +- compatible: should be "ti,sci-pm-domain"
>>>>>>> +- #power-domain-cells: Must be 0.
>>>>>>> +- ti,sci: Phandle to the TI SCI device to use for managing the
>>>>>>> devices.
>>>>>>>
>>>>>>> +Example:
>>>>>>> +--------------------
>>>>>>> +k2g_pds: k2g_pds {
>>>>>>
>>>>>>
>>>>>> should use generic name like "power-contoller", e.g. k2g_pds:
>>>>>> power-controller
>>>>>
>>>>>
>>>>> Ok, that makes more sense.
>>>>>
>>>>>>
>>>>>>> +        compatible = "ti,sci-pm-domain";
>>>>>>> +        #power-domain-cells = <0>;
>>>>>>> +        ti,sci = <&pmmc>;
>>>>>>> +};
>>>>>>> +
>>>>>>> +PM Domain Consumers
>>>>>>> +===================
>>>>>>> +Hardware blocks that require SCI control over their state must
>>>>>>> provide
>>>>>>> +a reference to the sci-pm-domain they are part of and a unique
>>>>>>> device
>>>>>>> +specific ID that identifies the device.
>>>>>>> +
>>>>>>> +Required Properties:
>>>>>>> +--------------------
>>>>>>> +- power-domains: phandle pointing to the corresponding PM domain
>>>>>>> node.
>>>>>>> +- ti,sci-id: index representing the device id to be passed oevr SCI
>>>>>>> to
>>>>>>> +        be used for device control.
>>>>>>
>>>>>>
>>>>>> This ID doesn't look right.
>>>>>>
>>>>>> Why not use #power-domain-cells = <1> and pass the index in the DT?
>>>>>> ...
>>>
>>>
>>> Exactly. ti,sci-id is a NAK for me.
>>
>>
>> I was told not to use the onecell during v1 discussion. I agree this would
>> be
>> ideal but I cannot due to what the bindings represent, the phandle
>> parameter is
>> an index into a list of genpds, whereas we need an actual ID number we can
>> use
>> and I do not have the ability to get that from the phandle.
>>
>> @Ulf/Jon, is there any hope of bringing back custom xlate functions for
>> genpd
>> providers? I don't have a good background on why it was even removed. I
>> can
>> maintain a single genpd for all devices but I need a way to parse this ID,
>> whether it's from a separate property or a phandle. It is locked now to
>> indexing
>> into a list of genpds but I need additional per device information for
>> devices
>> bound to a genpd and I need either a custom parameter or the ability to
>> parse
>> the phandle myself.
>>
>
> Any comments here? The meaning of the phandle onecell is fixed in the genpd
> framework so I'm not sure how we want to move forward with this, I need to
> pass a power domain ID to the genpd driver, and if this shouldn't be a new
> property I'm not sure what direction we should take.
>
> Regards,
> Dave
>
>
>>>
>>>>>>
>>>>>>> +See dt-bindings/genpd/k2g.h for the list of valid identifiers for
>>>>>>> k2g.
>>>>>>> +
>>>>>>> +Example:
>>>>>>> +--------------------
>>>>>>> +uart0: serial@02530c00 {
>>>>>>> +   compatible = "ns16550a";
>>>>>>> +   ...
>>>>>>> +   power-domains = <&k2g_pds>;
>>>>>>> +   ti,sci-id = <K2G_DEV_UART0>;
>>>>>>
>>>>>>
>>>>>> ... like this:
>>>>>>
>>>>>>      power-domains = <&k2g_pds K2G_DEV_UART0>;
>>>>>
>>>>>
>>>>> That's how I did it in version one actually. I was able to define my
>>>>> own xlate function to parse the phandle and get that index, but Ulf
>>>>> pointed me to this series by Jon Hunter [1] that simplified genpd
>>>>> providers and dropped the concept of adding your own xlate. This locks
>>>>> the onecell approach to using a fixed static array of genpds that get
>>>>> indexed into (without passing the index to the provider, just the
>>>>> genpd that's looked up), which doesn't fit our usecase, as we don't
>>>>> want a 1 to 1 genpd to device mapping based on the comments provided
>>>>> in v1. Now we just use the genpd device attach/detach hooks to parse
>>>>> the sci-id and then use it in the genpd device start/stop hooks.
>>>
>>>
>>> I have no idea what any of this means. All sounds like driver
>>> architecture, not anything to do with bindings.
>>
>>
>> This was a response to Kevin, not part of binding description.
>>
>>>
>>>>
>>>> Ah, right.  I remember now.  This approach allows you to use a single
>>>> genpd as discussed earlier.
>>>>
>>>> Makes sense now, suggestion retracted.
>>>
>>>
>>> IIRC, the bindings in Jon's case had a node for each domain and didn't
>>> need any additional property.
>>
>>
>> Yes but we only have one domain and index into it, not into a list of
>> domains,

Exactly. And this my main point as well. We are not talking about a
domain property but a device property.

>> so the additional property is solving a different problem.

Yes.

Perhaps you could try to elaborate about what the TI SCI ID really
represents for the device, as to help Rob understand the bigger
picture?

To me, the TI SCI ID, is similar to a "conid" for any another "device
resource" (like clock, pinctrl, regulator etc) which we can describe
in DT and assign to a device node. The only difference here, is that
we don't have common API to fetch the resource (like clk_get(),
regulator_get()), but instead we fetches the device's resource from
SoC specific code, via genpd's device ->attach() callback.

Hope that helps.

Kind regards
Uffe

^ permalink raw reply

* Re: [PATCH v5] media: et8ek8: add device tree binding documentation
From: Pavel Machek @ 2016-11-11 12:17 UTC (permalink / raw)
  To: Rob Herring
  Cc: ivo.g.dimitrov.75-Re5JQEeQqe8AvxtiuMwx3w,
	sakari.ailus-X3B1VOXEql0, sre-DgEjT+Ai2ygdnm+yROfE0A,
	pali.rohar-Re5JQEeQqe8AvxtiuMwx3w,
	linux-media-u79uwXL29TY76Z2rM5mHXA, pawel.moll-5wv7dgnIgG8,
	mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ, mchehab-JPH+aEBZ4P+UEJcrhfAQsw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20161107104648.GB5326@amd>

[-- Attachment #1: Type: text/plain, Size: 2392 bytes --]

On Mon 2016-11-07 11:46:48, Pavel Machek wrote:
> Add device tree binding documentation for toshiba et8ek8 sensor.
> 
> Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>

Rob, can we get an ack here?

Thanks,
							Pavel

> diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt
> new file mode 100644
> index 0000000..b03b21d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt
> @@ -0,0 +1,53 @@
> +Toshiba et8ek8 5MP sensor
> +
> +Toshiba et8ek8 5MP sensor is an image sensor found in Nokia N900 device
> +
> +More detailed documentation can be found in
> +Documentation/devicetree/bindings/media/video-interfaces.txt .
> +
> +
> +Mandatory properties
> +--------------------
> +
> +- compatible: "toshiba,et8ek8"
> +- reg: I2C address (0x3e, or an alternative address)
> +- vana-supply: Analogue voltage supply (VANA), 2.8 volts
> +- clocks: External clock to the sensor
> +- clock-frequency: Frequency of the external clock to the sensor. Camera
> +  driver will set this frequency on the external clock. The clock frequency is
> +  a pre-determined frequency known to be suitable to the board.
> +- reset-gpios: XSHUTDOWN GPIO. The XSHUTDOWN signal is active high. The sensor
> +  is in hardware standby mode when the signal is in low state.
> +
> +
> +Endpoint node mandatory properties
> +----------------------------------
> +
> +- remote-endpoint: A phandle to the bus receiver's endpoint node.
> +
> +Endpoint node optional properties
> +----------------------------------
> +
> +- clock-lanes: <0>
> +- data-lanes: <1..n>
> +
> +Example
> +-------
> +
> +&i2c3 {
> +	clock-frequency = <400000>;
> +
> +	cam1: camera@3e {
> +		compatible = "toshiba,et8ek8";
> +		reg = <0x3e>;
> +		vana-supply = <&vaux4>;
> +		clocks = <&isp 0>;
> +		clock-frequency = <9600000>;
> +		reset-gpio = <&gpio4 6 GPIO_ACTIVE_HIGH>; /* 102 */
> +		port {
> +			csi_cam1: endpoint {
> +				remote-endpoint = <&csi_out1>;
> +			};
> +		};
> +	};
> +};
> 
> 



-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply

* Re: [RESEND PATCH v1 02/11] dt-bindings: hisi: Add Hisilicon HiP05/06/07 Sysctrl and Djtag dts bindings
From: Anurup M @ 2016-11-11 11:59 UTC (permalink / raw)
  To: Mark Rutland
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-doc-u79uwXL29TY76Z2rM5mHXA, will.deacon-5wv7dgnIgG8,
	corbet-T1hC0tSOHrs, catalin.marinas-5wv7dgnIgG8,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, arnd-r2nGTMty4D4,
	f.fainelli-Re5JQEeQqe8AvxtiuMwx3w,
	rmk+kernel-lFZ/pmaqli7XmaaqVzeoHQ, krzk-DgEjT+Ai2ygdnm+yROfE0A,
	anurup.m-hv44wF8Li93QT0dZR+AlfA,
	zhangshaokun-C8/M+/jPZTeaMJb+Lgu22Q,
	tanxiaojun-hv44wF8Li93QT0dZR+AlfA, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q,
	sanil.kumar-C8/M+/jPZTeaMJb+Lgu22Q,
	john.garry-hv44wF8Li93QT0dZR+AlfA,
	gabriele.paoloni-hv44wF8Li93QT0dZR+AlfA,
	shiju.jose-hv44wF8Li93QT0dZR+AlfA,
	wangkefeng.wang-hv44wF8Li93QT0dZR+AlfA,
	guohanjun-hv44wF8Li93QT0dZR+AlfA, shyju.pv-hv44wF8Li93QT0dZR+AlfA,
	linuxarm-hv44wF8Li93QT0dZR+AlfA
In-Reply-To: <20161111115346.GC11945@leverpostej>



On Friday 11 November 2016 05:23 PM, Mark Rutland wrote:
> On Fri, Nov 11, 2016 at 04:49:03PM +0530, Anurup M wrote:
>> On Thursday 10 November 2016 10:53 PM, Mark Rutland wrote:
>>> On Thu, Nov 03, 2016 at 01:41:58AM -0400, Anurup M wrote:
>>>> diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
>>>> +Example:
>>>> +	/* for Hisilicon HiP05 djtag for CPU sysctrl */
>>>> +	djtag0: djtag@80010000 {
>>>> +		compatible = "hisilicon,hip05-cpu-djtag-v1";
>>>> +		reg = <0x0 0x80010000 0x0 0x10000>;
>>>> +
>>>> +		/* For L3 cache PMU */
>>>> +		pmul3c0 {
>>>> +			compatible = "hisilicon,hisi-pmu-l3c-v1";
>>>> +			scl-id = <0x02>;
>>>> +			num-events = <0x16>;
>>>> +			num-counters = <0x08>;
>>>> +			module-id = <0x04>;
>>>> +			num-banks = <0x04>;
>>>> +			cfgen-map = <0x02 0x04 0x01 0x08>;
>>>> +			counter-reg = <0x170>;
>>>> +			evctrl-reg = <0x04>;
>>>> +			event-en = <0x1000000>;
>>>> +			evtype-reg = <0x140>;
>>>> +		};
>>> This sub-node needs a binding document.
>>>
>>> These properties are completely opaque
>> The L3 cache PMU bindings are defined @bindings/arm/hisilicon/pmu.txt.
>> Is it OK that I document here(hisilicon/djtag.txt), a reference to
>> the PMU bindings doc ?
> At this point in the series, that file does not exist yet, and this is
> an undocumented beinding.
>
> Please introduce this sub-node long with the PMU bindings, later in the
> series.
Thanks, I got your suggestion. Will add this later in series.
> Thanks,
> Mark.

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [RESEND PATCH v1 02/11] dt-bindings: hisi: Add Hisilicon HiP05/06/07 Sysctrl and Djtag dts bindings
From: Mark Rutland @ 2016-11-11 11:53 UTC (permalink / raw)
  To: Anurup M
  Cc: devicetree, linux-arm-kernel, linux-doc, will.deacon, corbet,
	catalin.marinas, robh+dt, arnd, f.fainelli, rmk+kernel, krzk,
	anurup.m, zhangshaokun, tanxiaojun, xuwei5, sanil.kumar,
	john.garry, gabriele.paoloni, shiju.jose, wangkefeng.wang,
	guohanjun, shyju.pv, linuxarm
In-Reply-To: <5825A927.2000202@gmail.com>

On Fri, Nov 11, 2016 at 04:49:03PM +0530, Anurup M wrote:
> On Thursday 10 November 2016 10:53 PM, Mark Rutland wrote:
> >On Thu, Nov 03, 2016 at 01:41:58AM -0400, Anurup M wrote:

> >>diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt

> >>+Example:
> >>+	/* for Hisilicon HiP05 djtag for CPU sysctrl */
> >>+	djtag0: djtag@80010000 {
> >>+		compatible = "hisilicon,hip05-cpu-djtag-v1";
> >>+		reg = <0x0 0x80010000 0x0 0x10000>;
> >>+
> >>+		/* For L3 cache PMU */
> >>+		pmul3c0 {
> >>+			compatible = "hisilicon,hisi-pmu-l3c-v1";
> >>+			scl-id = <0x02>;
> >>+			num-events = <0x16>;
> >>+			num-counters = <0x08>;
> >>+			module-id = <0x04>;
> >>+			num-banks = <0x04>;
> >>+			cfgen-map = <0x02 0x04 0x01 0x08>;
> >>+			counter-reg = <0x170>;
> >>+			evctrl-reg = <0x04>;
> >>+			event-en = <0x1000000>;
> >>+			evtype-reg = <0x140>;
> >>+		};
> >This sub-node needs a binding document.
> >
> >These properties are completely opaque
> The L3 cache PMU bindings are defined @bindings/arm/hisilicon/pmu.txt.
> Is it OK that I document here(hisilicon/djtag.txt), a reference to
> the PMU bindings doc ?

At this point in the series, that file does not exist yet, and this is
an undocumented beinding.

Please introduce this sub-node long with the PMU bindings, later in the
series.

Thanks,
Mark.

^ permalink raw reply

* Re: [PATCH] PM / Domains: Fix compatible for domain idle state
From: Ulf Hansson @ 2016-11-11 11:52 UTC (permalink / raw)
  To: Rob Herring
  Cc: Lina Iyer, Kevin Hilman, Rafael J. Wysocki,
	linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	Andy Gross, Stephen Boyd,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Brendan Jackman, Lorenzo Pieralisi, Sudeep Holla, Juri Lelli,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <20161110195832.4nz7lxlmshaemcbb@rob-hp-laptop>

On 10 November 2016 at 20:58, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
>
> On Mon, Nov 07, 2016 at 12:14:28PM +0100, Ulf Hansson wrote:
> > On 3 November 2016 at 22:54, Lina Iyer <lina.iyer-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> > > Re-using idle state definition provided by arm,idle-state for domain
> > > idle states creates a lot of confusion and limits further evolution of
> > > the domain idle definition. To keep things clear and simple, define a
> > > idle states for domain using a new compatible "domain-idle-state".
> > >
> > > Fix existing PM domains code to look for the newly defined compatible.
> > >
> > > Cc: <devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
> > > Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> > > Signed-off-by: Lina Iyer <lina.iyer-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> > > ---
> > >  .../bindings/power/domain-idle-state.txt           | 33 ++++++++++++++++++++++
> > >  .../devicetree/bindings/power/power_domain.txt     |  8 +++---
> > >  drivers/base/power/domain.c                        |  2 +-
> > >  3 files changed, 38 insertions(+), 5 deletions(-)
> > >  create mode 100644 Documentation/devicetree/bindings/power/domain-idle-state.txt
> > >
> > > diff --git a/Documentation/devicetree/bindings/power/domain-idle-state.txt b/Documentation/devicetree/bindings/power/domain-idle-state.txt
> > > new file mode 100644
> > > index 0000000..eefc7ed
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/power/domain-idle-state.txt
> > > @@ -0,0 +1,33 @@
> > > +PM Domain Idle State Node:
> > > +
> > > +A domain idle state node represents the state parameters that will be used to
> > > +select the state when there are no active components in the domain.
> > > +
> > > +The state node has the following parameters -
> > > +
> > > +- compatible:
> > > +       Usage: Required
> > > +       Value type: <string>
> > > +       Definition: Must be "domain-idle-state".
> > > +
> > > +- entry-latency-us
> > > +       Usage: Required
> > > +       Value type: <prop-encoded-array>
> > > +       Definition: u32 value representing worst case latency in
> > > +                   microseconds required to enter the idle state.
> > > +                   The exit-latency-us duration may be guaranteed
> > > +                   only after entry-latency-us has passed.
> >
> > As we anyway are going to change this, why not use an u64 and have the
> > value in ns instead of us?
>
> I can't imagine that you would need more resolution or range. For times
> less than 1us, s/w and register access times are going to dominate the
> time.

Yep.

>
>
> Unless there is a real need, I'd keep alignment with the existing
> binding.

Agree!

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox