Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v6 2/2] media: i2c: Add the ov7740 image sensor driver
From: Yang, Wenyou @ 2017-12-06  5:38 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Nicolas Ferre,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Jonathan Corbet, Hans Verkuil,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Linux Media Mailing List, Songjun Wu
In-Reply-To: <20171205104549.aoturlmm3s6net37-S+BSfZ9RZZmRSg0ZkenSGLdO1Tsj/99ntUK59QYPAWc@public.gmane.org>

Hi Sakari,


On 2017/12/5 18:45, Sakari Ailus wrote:
> Hi Wenyou,
>
> On Mon, Dec 04, 2017 at 02:58:58PM +0800, Wenyou Yang wrote:
>> The ov7740 (color) image sensor is a high performance VGA CMOS
>> image snesor, which supports for output formats: RAW RGB and YUV
>> and image sizes: VGA, and QVGA, CIF and any size smaller.
>>
>> Signed-off-by: Songjun Wu <songjun.wu-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
>> Signed-off-by: Wenyou Yang <wenyou.yang-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
>> ---
>>
>> Changes in v6:
>>   - Remove unnecessary #include <linux/init>.
>>   - Remove unnecessary comments and extra newline.
>>   - Add const for some structures.
>>   - Add the check of the return value from regmap_write().
>>   - Simplify the calling of __v4l2_ctrl_handler_setup().
>>   - Add the default format initialization function.
>>   - Integrate the set_power() and enable/disable the clock into
>>     one function.
>>
>> Changes in v5:
>>   - Squash the driver and MAINTAINERS entry patches to one.
>>   - Precede the driver patch with the bindings patch.
>>
>> Changes in v4:
>>   - Assign 'val' a initial value to avoid warning: 'val' may be
>>     used uninitialized.
>>   - Rename REG_REG15 to avoid warning: "REG_REG15" redefined.
>>
>> Changes in v3:
>>   - Put the MAINTAINERS change to a separate patch.
>>
>> Changes in v2:
>>   - Split off the bindings into a separate patch.
>>   - Add a new entry to the MAINTAINERS file.
>>
>>   MAINTAINERS                |    8 +
>>   drivers/media/i2c/Kconfig  |    8 +
>>   drivers/media/i2c/Makefile |    1 +
>>   drivers/media/i2c/ov7740.c | 1226 ++++++++++++++++++++++++++++++++++++++++++++
>>   4 files changed, 1243 insertions(+)
>>   create mode 100644 drivers/media/i2c/ov7740.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 7a52a66aa991..1de965009b13 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -10053,6 +10053,14 @@ S:	Maintained
>>   F:	drivers/media/i2c/ov7670.c
>>   F:	Documentation/devicetree/bindings/media/i2c/ov7670.txt
>>   
>> +OMNIVISION OV7740 SENSOR DRIVER
>> +M:	Wenyou Yang <wenyou.yang-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
>> +L:	linux-media-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> +T:	git git://linuxtv.org/media_tree.git
>> +S:	Maintained
>> +F:	drivers/media/i2c/ov7740.c
>> +F:	Documentation/devicetree/bindings/media/i2c/ov7740.txt
>> +
>>   ONENAND FLASH DRIVER
>>   M:	Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>>   L:	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
>> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
>> index cb5d7ff82915..00b1c4c031d4 100644
>> --- a/drivers/media/i2c/Kconfig
>> +++ b/drivers/media/i2c/Kconfig
>> @@ -665,6 +665,14 @@ config VIDEO_OV7670
>>   	  OV7670 VGA camera.  It currently only works with the M88ALP01
>>   	  controller.
>>   
>> +config VIDEO_OV7740
>> +	tristate "OmniVision OV7740 sensor support"
>> +	depends on I2C && VIDEO_V4L2
>> +	depends on MEDIA_CAMERA_SUPPORT
>> +	---help---
>> +	  This is a Video4Linux2 sensor-level driver for the OmniVision
>> +	  OV7740 VGA camera sensor.
>> +
>>   config VIDEO_OV9650
>>   	tristate "OmniVision OV9650/OV9652 sensor support"
>>   	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
>> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
>> index 548a9efce966..9b19ec7fcaf4 100644
>> --- a/drivers/media/i2c/Makefile
>> +++ b/drivers/media/i2c/Makefile
>> @@ -68,6 +68,7 @@ obj-$(CONFIG_VIDEO_OV5670) += ov5670.o
>>   obj-$(CONFIG_VIDEO_OV6650) += ov6650.o
>>   obj-$(CONFIG_VIDEO_OV7640) += ov7640.o
>>   obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
>> +obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
>>   obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
>>   obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
>>   obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
>> diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
>> new file mode 100644
>> index 000000000000..42c25277d005
>> --- /dev/null
>> +++ b/drivers/media/i2c/ov7740.c
>> @@ -0,0 +1,1226 @@
>> +/*
>> + * Copyright (c) 2017 Microchip 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.
>> + *
>> + */
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/gpio.h>
>> +#include <linux/i2c.h>
>> +#include <linux/module.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/regmap.h>
>> +#include <media/v4l2-ctrls.h>
>> +#include <media/v4l2-event.h>
>> +#include <media/v4l2-image-sizes.h>
>> +#include <media/v4l2-subdev.h>
>> +
>> +#define REG_OUTSIZE_LSB 0x34
>> +
>> +/* OV7740 register tables */
>> +#define REG_GAIN	0x00	/* Gain lower 8 bits (rest in vref) */
>> +#define REG_BGAIN	0x01	/* blue gain */
>> +#define REG_RGAIN	0x02	/* red gain */
>> +#define REG_GGAIN	0x03	/* green gain */
>> +#define REG_REG04	0x04	/* analog setting, dont change*/
>> +#define REG_BAVG	0x05	/* b channel average */
>> +#define REG_GAVG	0x06	/* g channel average */
>> +#define REG_RAVG	0x07	/* r channel average */
>> +
>> +#define REG_REG0C	0x0C	/* filp enable */
>> +#define REG0C_IMG_FLIP		0x80
>> +#define REG0C_IMG_MIRROR	0x40
>> +
>> +#define REG_REG0E	0x0E	/* blc line */
>> +#define REG_HAEC	0x0F	/* auto exposure cntrl */
>> +#define REG_AEC		0x10	/* auto exposure cntrl */
>> +
>> +#define REG_CLK		0x11	/* Clock control */
>> +#define REG_REG55	0x55	/* Clock PLL DIV/PreDiv */
>> +
>> +#define REG_REG12	0x12
>> +
>> +#define REG_REG13	0x13	/* auto/manual AGC, AEC, Write Balance*/
>> +#define REG13_AEC_EN	0x01
>> +#define REG13_AGC_EN	0x04
>> +
>> +#define REG_REG14	0x14
>> +#define REG_CTRL15	0x15
>> +#define REG15_GAIN_MSB	0x03
>> +
>> +#define REG_REG16	0x16
>> +
>> +#define REG_MIDH	0x1C	/* manufacture id byte */
>> +#define REG_MIDL	0x1D	/* manufacture id byre */
>> +#define REG_PIDH	0x0A	/* Product ID MSB */
>> +#define REG_PIDL	0x0B	/* Product ID LSB */
>> +
>> +#define REG_84		0x84	/* lots of stuff */
>> +#define REG_REG38	0x38	/* sub-addr */
>> +
>> +#define REG_AHSTART	0x17	/* Horiz start high bits */
>> +#define REG_AHSIZE	0x18
>> +#define REG_AVSTART	0x19	/* Vert start high bits */
>> +#define REG_AVSIZE	0x1A
>> +#define REG_PSHFT	0x1b	/* Pixel delay after HREF */
>> +
>> +#define REG_HOUTSIZE	0x31
>> +#define REG_VOUTSIZE	0x32
>> +#define REG_HVSIZEOFF	0x33
>> +#define REG_REG34	0x34	/* DSP output size H/V LSB*/
>> +
>> +#define REG_ISP_CTRL00	0x80
>> +#define ISPCTRL00_AWB_EN	0x10
>> +#define ISPCTRL00_AWB_GAIN_EN	0x04
>> +
>> +#define	REG_YGAIN	0xE2	/* ygain for contrast control */
>> +
>> +#define	REG_YBRIGHT	  0xE3
>> +#define	REG_SGNSET	  0xE4
>> +#define	SGNSET_YBRIGHT_MASK	  0x08
>> +
>> +#define REG_USAT	0xDD
>> +#define REG_VSAT	0xDE
>> +
>> +
>> +struct ov7740 {
>> +	struct v4l2_subdev subdev;
>> +#if defined(CONFIG_MEDIA_CONTROLLER)
>> +	struct media_pad pad;
>> +#endif
>> +	struct v4l2_mbus_framefmt format;
>> +	const struct ov7740_pixfmt *fmt;  /* Current format */
>> +	const struct ov7740_framesize *frmsize;
>> +	struct regmap *regmap;
>> +	struct clk *xvclk;
>> +	struct v4l2_ctrl_handler ctrl_handler;
>> +	struct {
>> +		/* gain cluster */
>> +		struct v4l2_ctrl *auto_gain;
>> +		struct v4l2_ctrl *gain;
>> +	};
>> +	struct {
>> +		struct v4l2_ctrl *auto_wb;
>> +		struct v4l2_ctrl *blue_balance;
>> +		struct v4l2_ctrl *red_balance;
>> +	};
>> +	struct {
>> +		struct v4l2_ctrl *hflip;
>> +		struct v4l2_ctrl *vflip;
>> +	};
>> +	struct {
>> +		/* exposure cluster */
>> +		struct v4l2_ctrl *auto_exposure;
>> +		struct v4l2_ctrl *exposure;
>> +	};
>> +	struct {
>> +		/* saturation/hue cluster */
>> +		struct v4l2_ctrl *saturation;
>> +		struct v4l2_ctrl *hue;
>> +	};
>> +	struct v4l2_ctrl *brightness;
>> +	struct v4l2_ctrl *contrast;
>> +
>> +	struct mutex mutex;	/* To serialize asynchronus callbacks */
>> +	bool streaming;		/* Streaming on/off */
>> +
>> +	struct gpio_desc *resetb_gpio;
>> +	struct gpio_desc *pwdn_gpio;
>> +};
>> +
>> +struct ov7740_pixfmt {
>> +	u32 mbus_code;
>> +	enum v4l2_colorspace colorspace;
>> +	const struct reg_sequence *regs;
>> +	u32 reg_num;
>> +};
>> +
>> +struct ov7740_framesize {
>> +	u16 width;
>> +	u16 height;
>> +	const struct reg_sequence *regs;
>> +	u32 reg_num;
>> +};
>> +
>> +static const struct reg_sequence ov7740_vga[] = {
>> +	{0x55, 0x40},
>> +	{0x11, 0x02},
>> +
>> +	{0xd5, 0x10},
>> +	{0x0c, 0x12},
>> +	{0x0d, 0x34},
>> +	{0x17, 0x25},
>> +	{0x18, 0xa0},
>> +	{0x19, 0x03},
>> +	{0x1a, 0xf0},
>> +	{0x1b, 0x89},
>> +	{0x22, 0x03},
>> +	{0x29, 0x18},
>> +	{0x2b, 0xf8},
>> +	{0x2c, 0x01},
>> +	{REG_HOUTSIZE, 0xa0},
>> +	{REG_VOUTSIZE, 0xf0},
>> +	{0x33, 0xc4},
>> +	{REG_OUTSIZE_LSB, 0x0},
>> +	{0x35, 0x05},
>> +	{0x04, 0x60},
>> +	{0x27, 0x80},
>> +	{0x3d, 0x0f},
>> +	{0x3e, 0x80},
>> +	{0x3f, 0x40},
>> +	{0x40, 0x7f},
>> +	{0x41, 0x6a},
>> +	{0x42, 0x29},
>> +	{0x44, 0x22},
>> +	{0x45, 0x41},
>> +	{0x47, 0x02},
>> +	{0x49, 0x64},
>> +	{0x4a, 0xa1},
>> +	{0x4b, 0x40},
>> +	{0x4c, 0x1a},
>> +	{0x4d, 0x50},
>> +	{0x4e, 0x13},
>> +	{0x64, 0x00},
>> +	{0x67, 0x88},
>> +	{0x68, 0x1a},
>> +
>> +	{0x14, 0x28},
>> +	{0x24, 0x3c},
>> +	{0x25, 0x30},
>> +	{0x26, 0x72},
>> +	{0x50, 0x97},
>> +	{0x51, 0x1f},
>> +	{0x52, 0x00},
>> +	{0x53, 0x00},
>> +	{0x20, 0x00},
>> +	{0x21, 0xcf},
>> +	{0x50, 0x4b},
>> +	{0x38, 0x14},
>> +	{0xe9, 0x00},
>> +	{0x56, 0x55},
>> +	{0x57, 0xff},
>> +	{0x58, 0xff},
>> +	{0x59, 0xff},
>> +	{0x5f, 0x04},
>> +	{0xec, 0x00},
>> +	{0x13, 0xff},
>> +
>> +	{0x81, 0x3f},
>> +	{0x82, 0x32},
>> +	{0x38, 0x11},
>> +	{0x84, 0x70},
>> +	{0x85, 0x00},
>> +	{0x86, 0x03},
>> +	{0x87, 0x01},
>> +	{0x88, 0x05},
>> +	{0x89, 0x30},
>> +	{0x8d, 0x30},
>> +	{0x8f, 0x85},
>> +	{0x93, 0x30},
>> +	{0x95, 0x85},
>> +	{0x99, 0x30},
>> +	{0x9b, 0x85},
>> +
>> +	{0x9c, 0x08},
>> +	{0x9d, 0x12},
>> +	{0x9e, 0x23},
>> +	{0x9f, 0x45},
>> +	{0xa0, 0x55},
>> +	{0xa1, 0x64},
>> +	{0xa2, 0x72},
>> +	{0xa3, 0x7f},
>> +	{0xa4, 0x8b},
>> +	{0xa5, 0x95},
>> +	{0xa6, 0xa7},
>> +	{0xa7, 0xb5},
>> +	{0xa8, 0xcb},
>> +	{0xa9, 0xdd},
>> +	{0xaa, 0xec},
>> +	{0xab, 0x1a},
>> +
>> +	{0xce, 0x78},
>> +	{0xcf, 0x6e},
>> +	{0xd0, 0x0a},
>> +	{0xd1, 0x0c},
>> +	{0xd2, 0x84},
>> +	{0xd3, 0x90},
>> +	{0xd4, 0x1e},
>> +
>> +	{0x5a, 0x24},
>> +	{0x5b, 0x1f},
>> +	{0x5c, 0x88},
>> +	{0x5d, 0x60},
>> +
>> +	{0xac, 0x6e},
>> +	{0xbe, 0xff},
>> +	{0xbf, 0x00},
>> +
>> +	{0x0f, 0x1d},
>> +	{0x0f, 0x1f},
>> +};
>> +
>> +static const struct ov7740_framesize ov7740_framesizes[] = {
>> +	{
>> +		.width		= VGA_WIDTH,
>> +		.height		= VGA_HEIGHT,
>> +		.regs		= ov7740_vga,
>> +		.reg_num	= ARRAY_SIZE(ov7740_vga),
>> +	},
>> +};
>> +
>> +#ifdef CONFIG_VIDEO_ADV_DEBUG
>> +static int ov7740_get_register(struct v4l2_subdev *sd,
>> +			       struct v4l2_dbg_register *reg)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +	struct regmap *regmap = ov7740->regmap;
>> +	unsigned int val = 0;
>> +	int ret;
>> +
>> +	ret = regmap_read(regmap, reg->reg & 0xff, &val);
>> +	reg->val = val;
>> +	reg->size = 1;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_set_register(struct v4l2_subdev *sd,
>> +			       const struct v4l2_dbg_register *reg)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +	struct regmap *regmap = ov7740->regmap;
>> +
>> +	regmap_write(regmap, reg->reg & 0xff, reg->val & 0xff);
>> +
>> +	return 0;
>> +}
>> +#endif
>> +
>> +static int ov7740_set_power(struct ov7740 *ov7740, int on)
>> +{
>> +	int ret;
>> +
>> +	if (on) {
>> +		ret = clk_prepare_enable(ov7740->xvclk);
>> +		if (ret)
>> +			return ret;
>> +
>> +		if (ov7740->pwdn_gpio)
>> +			gpiod_direction_output(ov7740->pwdn_gpio, 0);
>> +
>> +		if (ov7740->resetb_gpio) {
>> +			gpiod_set_value(ov7740->resetb_gpio, 1);
>> +			usleep_range(500, 1000);
>> +			gpiod_set_value(ov7740->resetb_gpio, 0);
>> +			usleep_range(3000, 5000);
>> +		}
>> +	} else {
>> +		clk_disable_unprepare(ov7740->xvclk);
>> +
>> +		if (ov7740->pwdn_gpio)
>> +			gpiod_direction_output(ov7740->pwdn_gpio, 0);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static struct v4l2_subdev_core_ops ov7740_subdev_core_ops = {
>> +	.log_status = v4l2_ctrl_subdev_log_status,
>> +#ifdef CONFIG_VIDEO_ADV_DEBUG
>> +	.g_register = ov7740_get_register,
>> +	.s_register = ov7740_set_register,
>> +#endif
>> +	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
>> +	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
>> +};
>> +
>> +static int ov7740_set_white_balance(struct ov7740 *ov7740, int awb)
>> +{
>> +	struct regmap *regmap = ov7740->regmap;
>> +	unsigned int value;
>> +	int ret;
>> +
>> +	ret = regmap_read(regmap, REG_ISP_CTRL00, &value);
>> +	if (!ret) {
>> +		if (awb)
>> +			value |= (ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN);
>> +		else
>> +			value &= ~(ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN);
>> +		ret = regmap_write(regmap, REG_ISP_CTRL00, value);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	if (!awb) {
>> +		ret = regmap_write(regmap, REG_BGAIN,
>> +				   ov7740->blue_balance->val);
>> +		if (ret)
>> +			return ret;
>> +
>> +		ret = regmap_write(regmap, REG_RGAIN, ov7740->red_balance->val);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_set_saturation(struct regmap *regmap, int value)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_write(regmap, REG_USAT, (unsigned char)value);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return regmap_write(regmap, REG_VSAT, (unsigned char)value);
>> +}
>> +
>> +static int ov7740_set_gain(struct regmap *regmap, int value)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_write(regmap, REG_GAIN, value & 0xff);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = regmap_update_bits(regmap, REG_CTRL15,
>> +				 REG15_GAIN_MSB, (value >> 8) & 0x3);
>> +	if (!ret)
>> +		ret = regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0);
>> +
>> +	return ret;
>> +}
>> +
>> +static int ov7740_set_autogain(struct regmap *regmap, int value)
>> +{
>> +	unsigned int reg;
>> +	int ret;
>> +
>> +	ret = regmap_read(regmap, REG_REG13, &reg);
>> +	if (ret)
>> +		return ret;
>> +	if (value)
>> +		reg |= REG13_AGC_EN;
>> +	else
>> +		reg &= ~REG13_AGC_EN;
>> +	return regmap_write(regmap, REG_REG13, reg);
>> +}
>> +
>> +static int ov7740_set_brightness(struct regmap *regmap, int value)
>> +{
>> +	/* Turn off AEC/AGC */
>> +	regmap_update_bits(regmap, REG_REG13, REG13_AEC_EN, 0);
>> +	regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0);
>> +
>> +	if (value >= 0) {
>> +		regmap_write(regmap, REG_YBRIGHT, (unsigned char)value);
>> +		regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 0);
>> +	} else{
>> +		regmap_write(regmap, REG_YBRIGHT, (unsigned char)(-value));
>> +		regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 1);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_set_contrast(struct regmap *regmap, int value)
>> +{
>> +	return regmap_write(regmap, REG_YGAIN, (unsigned char)value);
>> +}
>> +
>> +static int ov7740_get_gain(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl)
>> +{
>> +	struct regmap *regmap = ov7740->regmap;
>> +	unsigned int value0, value1;
>> +	int ret;
>> +
>> +	if (!ctrl->val)
>> +		return 0;
>> +
>> +	ret = regmap_read(regmap, REG_GAIN, &value0);
>> +	if (ret)
>> +		return ret;
>> +	ret = regmap_read(regmap, REG_CTRL15, &value1);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ov7740->gain->val = (value1 << 8) | (value0 & 0xff);
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_set_exp(struct regmap *regmap, int value)
>> +{
>> +	int ret;
>> +
>> +	/* Turn off AEC/AGC */
>> +	ret = regmap_update_bits(regmap, REG_REG13,
>> +				 REG13_AEC_EN | REG13_AGC_EN, 0);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = regmap_write(regmap, REG_AEC, (unsigned char)value);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return regmap_write(regmap, REG_HAEC, (unsigned char)(value >> 8));
>> +}
>> +
>> +static int ov7740_set_autoexp(struct regmap *regmap,
>> +			      enum v4l2_exposure_auto_type value)
>> +{
>> +	unsigned int reg;
>> +	int ret;
>> +
>> +	ret = regmap_read(regmap, REG_REG13, &reg);
>> +	if (!ret) {
>> +		if (value == V4L2_EXPOSURE_AUTO)
>> +			reg |= (REG13_AEC_EN | REG13_AGC_EN);
>> +		else
>> +			reg &= ~(REG13_AEC_EN | REG13_AGC_EN);
>> +		ret = regmap_write(regmap, REG_REG13, reg);
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +
>> +static int ov7740_get_volatile_ctrl(struct v4l2_ctrl *ctrl)
>> +{
>> +	struct ov7740 *ov7740 = container_of(ctrl->handler,
>> +					     struct ov7740, ctrl_handler);
>> +	int ret;
>> +
>> +	switch (ctrl->id) {
>> +	case V4L2_CID_AUTOGAIN:
>> +		ret = ov7740_get_gain(ov7740, ctrl);
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +		break;
>> +	}
>> +	return ret;
>> +}
>> +
>> +static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl)
>> +{
>> +	struct ov7740 *ov7740 = container_of(ctrl->handler,
>> +					     struct ov7740, ctrl_handler);
>> +	struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev);
>> +	struct regmap *regmap = ov7740->regmap;
>> +	int ret;
>> +	u8 val = 0;
>> +
>> +	if (pm_runtime_get_if_in_use(&client->dev) <= 0)
>> +		return 0;
>> +
>> +	switch (ctrl->id) {
>> +	case V4L2_CID_AUTO_WHITE_BALANCE:
>> +		ret = ov7740_set_white_balance(ov7740, ctrl->val);
>> +		break;
>> +	case V4L2_CID_SATURATION:
>> +		ret = ov7740_set_saturation(regmap, ctrl->val);
>> +		break;
>> +	case V4L2_CID_BRIGHTNESS:
>> +		ret = ov7740_set_brightness(regmap, ctrl->val);
>> +		break;
>> +	case V4L2_CID_CONTRAST:
>> +		ret = ov7740_set_contrast(regmap, ctrl->val);
>> +		break;
>> +	case V4L2_CID_VFLIP:
>> +		ret = regmap_update_bits(regmap, REG_REG0C,
>> +					 REG0C_IMG_FLIP, val);
>> +		break;
>> +	case V4L2_CID_HFLIP:
>> +		val = ctrl->val ? REG0C_IMG_MIRROR : 0x00;
>> +		ret = regmap_update_bits(regmap, REG_REG0C,
>> +					 REG0C_IMG_MIRROR, val);
>> +		break;
>> +	case V4L2_CID_AUTOGAIN:
>> +		if (!ctrl->val)
>> +			return ov7740_set_gain(regmap, ov7740->gain->val);
>> +
>> +		ret = ov7740_set_autogain(regmap, ctrl->val);
>> +		break;
>> +
>> +	case V4L2_CID_EXPOSURE_AUTO:
>> +		if (ctrl->val == V4L2_EXPOSURE_MANUAL)
>> +			return ov7740_set_exp(regmap, ov7740->exposure->val);
>> +
>> +		ret = ov7740_set_autoexp(regmap, ctrl->val);
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +		break;
>> +	}
>> +
>> +	pm_runtime_put(&client->dev);
>> +
>> +	return ret;
>> +}
>> +
>> +static const struct v4l2_ctrl_ops ov7740_ctrl_ops = {
>> +	.g_volatile_ctrl = ov7740_get_volatile_ctrl,
>> +	.s_ctrl = ov7740_set_ctrl,
>> +};
>> +
>> +static int ov7740_start_streaming(struct ov7740 *ov7740)
>> +{
>> +	return __v4l2_ctrl_handler_setup(ov7740->subdev.ctrl_handler);
>> +}
>> +
>> +static int ov7740_set_stream(struct v4l2_subdev *sd, int enable)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
>> +	int ret = 0;
>> +
>> +	mutex_lock(&ov7740->mutex);
>> +	if (ov7740->streaming == enable) {
>> +		mutex_unlock(&ov7740->mutex);
>> +		return 0;
>> +	}
>> +
>> +	if (enable) {
>> +		ret = pm_runtime_get_sync(&client->dev);
>> +		if (ret < 0) {
>> +			pm_runtime_put_noidle(&client->dev);
>> +			goto err_unlock;
>> +		}
>> +
>> +		ret = ov7740_start_streaming(ov7740);
>> +		if (ret)
>> +			goto err_rpm_put;
>> +	} else {
>> +		pm_runtime_put(&client->dev);
>> +	}
>> +
>> +	ov7740->streaming = enable;
>> +
>> +	mutex_unlock(&ov7740->mutex);
>> +	return ret;
>> +
>> +err_rpm_put:
>> +	pm_runtime_put(&client->dev);
>> +err_unlock:
>> +	mutex_unlock(&ov7740->mutex);
>> +	return ret;
>> +}
>> +
>> +static int ov7740_get_parm(struct v4l2_subdev *sd,
>> +			   struct v4l2_streamparm *parms)
>> +{
>> +	struct v4l2_captureparm *cp = &parms->parm.capture;
>> +	struct v4l2_fract *tpf = &cp->timeperframe;
>> +
>> +	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>> +		return -EINVAL;
>> +
>> +	memset(cp, 0, sizeof(struct v4l2_captureparm));
>> +	cp->capability = V4L2_CAP_TIMEPERFRAME;
>> +
>> +	tpf->numerator = 1;
>> +	tpf->denominator = 60;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_set_parm(struct v4l2_subdev *sd,
>> +			   struct v4l2_streamparm *parms)
>> +{
>> +	struct v4l2_captureparm *cp = &parms->parm.capture;
>> +	struct v4l2_fract *tpf = &cp->timeperframe;
>> +
>> +	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>> +		return -EINVAL;
>> +	if (cp->extendedmode != 0)
>> +		return -EINVAL;
>> +
>> +	cp->capability = V4L2_CAP_TIMEPERFRAME;
>> +
>> +	tpf->numerator = 1;
>> +	tpf->denominator = 60;
>> +
>> +	return 0;
>> +}
>> +
>> +static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {
>> +	.s_stream = ov7740_set_stream,
>> +	.s_parm = ov7740_set_parm,
>> +	.g_parm = ov7740_get_parm,
>> +};
>> +
>> +static const struct reg_sequence ov7740_format_yuyv[] = {
>> +	{0x12, 0x00},
>> +	{0x36, 0x3f},
>> +	{0x80, 0x7f},
>> +	{0x83, 0x01},
>> +};
>> +
>> +static const struct reg_sequence ov7740_format_bggr8[] = {
>> +	{0x36, 0x2f},
>> +	{0x80, 0x01},
>> +	{0x83, 0x04},
>> +};
>> +
>> +static const struct ov7740_pixfmt ov7740_formats[] = {
>> +	{
>> +		.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
>> +		.colorspace = V4L2_COLORSPACE_SRGB,
>> +		.regs = ov7740_format_yuyv,
>> +		.reg_num = ARRAY_SIZE(ov7740_format_yuyv),
>> +	},
>> +	{
>> +		.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
>> +		.colorspace = V4L2_COLORSPACE_SRGB,
>> +		.regs = ov7740_format_bggr8,
>> +		.reg_num = ARRAY_SIZE(ov7740_format_bggr8),
>> +	}
>> +};
>> +#define N_OV7740_FMTS ARRAY_SIZE(ov7740_formats)
>> +
>> +static int ov7740_enum_mbus_code(struct v4l2_subdev *sd,
>> +				 struct v4l2_subdev_pad_config *cfg,
>> +				 struct v4l2_subdev_mbus_code_enum *code)
>> +{
>> +	if (code->pad || code->index >= N_OV7740_FMTS)
>> +		return -EINVAL;
>> +
>> +	code->code = ov7740_formats[code->index].mbus_code;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_enum_frame_interval(struct v4l2_subdev *sd,
>> +				struct v4l2_subdev_pad_config *cfg,
>> +				struct v4l2_subdev_frame_interval_enum *fie)
>> +{
>> +	if (fie->pad)
>> +		return -EINVAL;
>> +
>> +	if (fie->index >= 1)
>> +		return -EINVAL;
>> +
>> +	if ((fie->width != VGA_WIDTH) || (fie->height != VGA_HEIGHT))
>> +		return -EINVAL;
>> +
>> +	fie->interval.numerator = 1;
>> +	fie->interval.denominator = 60;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_enum_frame_size(struct v4l2_subdev *sd,
>> +				  struct v4l2_subdev_pad_config *cfg,
>> +				  struct v4l2_subdev_frame_size_enum *fse)
>> +{
>> +	if (fse->pad)
>> +		return -EINVAL;
>> +
>> +	if (fse->index > 0)
>> +		return -EINVAL;
>> +
>> +	fse->min_width = fse->max_width = VGA_WIDTH;
>> +	fse->min_height = fse->max_height = VGA_HEIGHT;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_try_fmt_internal(struct v4l2_subdev *sd,
>> +				   struct v4l2_mbus_framefmt *fmt,
>> +				   const struct ov7740_pixfmt **ret_fmt,
>> +				   const struct ov7740_framesize **ret_frmsize)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +	const struct ov7740_framesize *fsize = &ov7740_framesizes[0];
>> +	int index, i;
>> +
>> +	for (index = 0; index < N_OV7740_FMTS; index++) {
>> +		if (ov7740_formats[index].mbus_code == fmt->code)
>> +			break;
>> +	}
>> +	if (index >= N_OV7740_FMTS) {
>> +		/* default to first format */
>> +		index = 0;
>> +		fmt->code = ov7740_formats[0].mbus_code;
>> +	}
>> +	if (ret_fmt != NULL)
>> +		*ret_fmt = ov7740_formats + index;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(ov7740_framesizes); i++) {
>> +		if ((fsize->width >= fmt->width) &&
>> +		    (fsize->height >= fmt->height)) {
>> +			fmt->width = fsize->width;
>> +			fmt->height = fsize->height;
>> +			break;
>> +		}
>> +
>> +		fsize++;
>> +	}
>> +
>> +	if (ret_frmsize != NULL)
>> +		*ret_frmsize = fsize;
>> +
>> +	fmt->field = V4L2_FIELD_NONE;
>> +	fmt->colorspace = ov7740_formats[index].colorspace;
>> +
>> +	ov7740->format = *fmt;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_set_fmt(struct v4l2_subdev *sd,
>> +			  struct v4l2_subdev_pad_config *cfg,
>> +			  struct v4l2_subdev_format *format)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +	const struct ov7740_pixfmt *ovfmt;
>> +	const struct ov7740_framesize *fsize;
>> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
>> +	struct v4l2_mbus_framefmt *mbus_fmt;
>> +#endif
>> +	int ret;
>> +
>> +	mutex_lock(&ov7740->mutex);
>> +	if (format->pad) {
>> +		ret = -EINVAL;
>> +		goto error;
>> +	}
>> +
>> +	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
>> +		ret = ov7740_try_fmt_internal(sd, &format->format, NULL, NULL);
>> +		if (ret)
>> +			goto error;
>> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
>> +		mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
>> +		*mbus_fmt = format->format;
>> +
>> +		mutex_unlock(&ov7740->mutex);
>> +		return 0;
>> +#else
>> +		ret = -ENOTTY;
>> +		goto error;
>> +#endif
>> +	}
>> +
>> +	ret = ov7740_try_fmt_internal(sd, &format->format, &ovfmt, &fsize);
>> +	if (ret)
>> +		goto error;
>> +
>> +	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
>> +		regmap_multi_reg_write(ov7740->regmap,
>> +				       ovfmt->regs, ovfmt->reg_num);
>> +
>> +		regmap_multi_reg_write(ov7740->regmap,
>> +				       fsize->regs, fsize->reg_num);
>> +	}
>> +
>> +	ov7740->fmt = ovfmt;
>> +
>> +	mutex_unlock(&ov7740->mutex);
>> +	return 0;
>> +
>> +error:
>> +	mutex_unlock(&ov7740->mutex);
>> +	return ret;
>> +}
>> +
>> +static int ov7740_get_fmt(struct v4l2_subdev *sd,
>> +			  struct v4l2_subdev_pad_config *cfg,
>> +			  struct v4l2_subdev_format *format)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
>> +	struct v4l2_mbus_framefmt *mbus_fmt;
>> +#endif
>> +	int ret = 0;
>> +
>> +	mutex_lock(&ov7740->mutex);
>> +	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
>> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
>> +		mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
>> +		format->format = *mbus_fmt;
>> +		ret = 0;
>> +#else
>> +		ret = -ENOTTY;
>> +#endif
>> +	} else {
>> +		format->format = ov7740->format;
>> +	}
>> +	mutex_unlock(&ov7740->mutex);
>> +
>> +	return ret;
>> +}
>> +
>> +static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = {
>> +	.enum_frame_interval = ov7740_enum_frame_interval,
>> +	.enum_frame_size = ov7740_enum_frame_size,
>> +	.enum_mbus_code = ov7740_enum_mbus_code,
>> +	.get_fmt = ov7740_get_fmt,
>> +	.set_fmt = ov7740_set_fmt,
>> +};
>> +
>> +static const struct v4l2_subdev_ops ov7740_subdev_ops = {
>> +	.core	= &ov7740_subdev_core_ops,
>> +	.video	= &ov7740_subdev_video_ops,
>> +	.pad	= &ov7740_subdev_pad_ops,
>> +};
>> +
>> +static void ov7740_get_default_format(struct v4l2_subdev *sd,
>> +				      struct v4l2_mbus_framefmt *format)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +
>> +	format->width = ov7740->frmsize->width;
>> +	format->height = ov7740->frmsize->height;
>> +	format->colorspace = ov7740->fmt->colorspace;
>> +	format->code = ov7740->fmt->mbus_code;
>> +	format->field = V4L2_FIELD_NONE;
>> +}
>> +
>> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
>> +static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +	struct v4l2_mbus_framefmt *format =
>> +				v4l2_subdev_get_try_format(sd, fh->pad, 0);
>> +
>> +	mutex_lock(&ov7740->mutex);
>> +	ov7740_get_default_format(sd, format);
>> +	mutex_unlock(&ov7740->mutex);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct v4l2_subdev_internal_ops ov7740_subdev_internal_ops = {
>> +	.open = ov7740_open,
>> +};
>> +#endif
>> +
>> +static void ov7740_init_default_format(struct ov7740 *ov7740)
>> +{
>> +	ov7740->frmsize = &ov7740_framesizes[0];
>> +	ov7740->fmt = &ov7740_formats[0];
>> +
>> +	regmap_multi_reg_write(ov7740->regmap,
>> +			       ov7740->fmt->regs, ov7740->fmt->reg_num);
>> +
>> +	regmap_multi_reg_write(ov7740->regmap,
>> +			       ov7740->frmsize->regs, ov7740->frmsize->reg_num);
>> +}
>> +
>> +static int ov7740_probe_dt(struct i2c_client *client,
>> +			   struct ov7740 *ov7740)
>> +{
>> +	ov7740->resetb_gpio = devm_gpiod_get_optional(&client->dev, "reset",
>> +			GPIOD_OUT_HIGH);
>> +	if (IS_ERR(ov7740->resetb_gpio)) {
>> +		dev_info(&client->dev, "can't get %s GPIO\n", "reset");
>> +		return PTR_ERR(ov7740->resetb_gpio);
>> +	}
>> +
>> +	ov7740->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
>> +			GPIOD_OUT_LOW);
>> +	if (IS_ERR(ov7740->pwdn_gpio)) {
>> +		dev_info(&client->dev, "can't get %s GPIO\n", "powerdown");
>> +		return PTR_ERR(ov7740->pwdn_gpio);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_detect(struct ov7740 *ov7740)
>> +{
>> +	struct regmap *regmap = ov7740->regmap;
>> +	unsigned int midh, midl, pidh, pidl;
>> +	int ret;
>> +
>> +	ret = regmap_read(regmap, REG_MIDH, &midh);
>> +	if (ret)
>> +		return ret;
>> +	if (midh != 0x7f)
>> +		return -ENODEV;
>> +
>> +	ret = regmap_read(regmap, REG_MIDL, &midl);
>> +	if (ret)
>> +		return ret;
>> +	if (midl != 0xa2)
>> +		return -ENODEV;
>> +
>> +	ret = regmap_read(regmap, REG_PIDH, &pidh);
>> +	if (ret)
>> +		return ret;
>> +	if (pidh != 0x77)
>> +		return -ENODEV;
>> +
>> +	ret = regmap_read(regmap, REG_PIDL, &pidl);
>> +	if (ret)
>> +		return ret;
>> +	if ((pidl != 0x40) && (pidl != 0x41) && (pidl != 0x42))
>> +		return -ENODEV;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_init_controls(struct ov7740 *ov7740)
>> +{
>> +	struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev);
>> +	struct v4l2_ctrl_handler *ctrl_hdlr = &ov7740->ctrl_handler;
>> +	int ret;
>> +
>> +	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 2);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	ctrl_hdlr->lock = &ov7740->mutex;
>> +	ov7740->auto_wb = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					  V4L2_CID_AUTO_WHITE_BALANCE,
>> +					  0, 1, 1, 1);
>> +	ov7740->blue_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					       V4L2_CID_BLUE_BALANCE,
>> +					       0, 0xff, 1, 0x80);
>> +	ov7740->red_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					      V4L2_CID_RED_BALANCE,
>> +					      0, 0xff, 1, 0x80);
>> +
>> +	ov7740->brightness = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					     V4L2_CID_BRIGHTNESS,
>> +					     -255, 255, 1, 0);
>> +	ov7740->contrast = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					   V4L2_CID_CONTRAST,
>> +					   0, 127, 1, 0x20);
>> +	ov7740->saturation = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +			  V4L2_CID_SATURATION, 0, 256, 1, 0x80);
>> +	ov7740->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					V4L2_CID_HFLIP, 0, 1, 1, 0);
>> +	ov7740->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					V4L2_CID_VFLIP, 0, 1, 1, 0);
>> +	ov7740->gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +				       V4L2_CID_GAIN, 0, 1023, 1, 500);
>> +	ov7740->auto_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					    V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
>> +	ov7740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					   V4L2_CID_EXPOSURE, 0, 65535, 1, 500);
>> +	ov7740->auto_exposure = v4l2_ctrl_new_std_menu(ctrl_hdlr,
>> +					&ov7740_ctrl_ops,
>> +					V4L2_CID_EXPOSURE_AUTO,
>> +					V4L2_EXPOSURE_MANUAL, 0,
>> +					V4L2_EXPOSURE_AUTO);
>> +
>> +	ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
>> +	ov7740->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
>> +
>> +	v4l2_ctrl_auto_cluster(3, &ov7740->auto_wb, 0, false);
>> +	v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true);
>> +	v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure,
>> +			       V4L2_EXPOSURE_MANUAL, false);
>> +	v4l2_ctrl_cluster(2, &ov7740->hflip);
>> +
>> +	ret = v4l2_ctrl_handler_setup(ctrl_hdlr);
>> +	if (ret) {
>> +		dev_err(&client->dev, "%s control init failed (%d)\n",
>> +			__func__, ret);
>> +		goto error;
>> +	}
>> +
>> +	ov7740->subdev.ctrl_handler = ctrl_hdlr;
>> +	return 0;
>> +
>> +error:
>> +	v4l2_ctrl_handler_free(ctrl_hdlr);
>> +	mutex_destroy(&ov7740->mutex);
>> +	return ret;
>> +}
>> +
>> +static void ov7740_free_controls(struct ov7740 *ov7740)
>> +{
>> +	v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
>> +	mutex_destroy(&ov7740->mutex);
>> +}
>> +
>> +#define OV7740_MAX_REGISTER     0xff
>> +static const struct regmap_config ov7740_regmap_config = {
>> +	.reg_bits	= 8,
>> +	.val_bits	= 8,
>> +	.max_register	= OV7740_MAX_REGISTER,
>> +};
>> +
>> +static int ov7740_probe(struct i2c_client *client,
>> +			const struct i2c_device_id *id)
>> +{
>> +	struct ov7740 *ov7740;
>> +	struct v4l2_subdev *sd;
>> +	int ret;
>> +
>> +	if (!i2c_check_functionality(client->adapter,
>> +				     I2C_FUNC_SMBUS_BYTE_DATA)) {
>> +		dev_err(&client->dev,
>> +			"OV7740: I2C-Adapter doesn't support SMBUS\n");
>> +		return -EIO;
>> +	}
>> +
>> +	ov7740 = devm_kzalloc(&client->dev, sizeof(*ov7740), GFP_KERNEL);
>> +	if (!ov7740)
>> +		return -ENOMEM;
>> +
>> +	ov7740->xvclk = devm_clk_get(&client->dev, "xvclk");
>> +	if (IS_ERR(ov7740->xvclk)) {
>> +		ret = PTR_ERR(ov7740->xvclk);
>> +		dev_err(&client->dev,
>> +			"OV7740: fail to get xvclk: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = ov7740_probe_dt(client, ov7740);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ov7740->regmap = devm_regmap_init_i2c(client, &ov7740_regmap_config);
>> +	if (IS_ERR(ov7740->regmap)) {
>> +		ret = PTR_ERR(ov7740->regmap);
>> +		dev_err(&client->dev, "Failed to allocate register map: %d\n",
>> +			ret);
>> +		return ret;
>> +	}
>> +
>> +	sd = &ov7740->subdev;
>> +	client->flags |= I2C_CLIENT_SCCB;
>> +	v4l2_i2c_subdev_init(sd, client, &ov7740_subdev_ops);
>> +
>> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
>> +	sd->internal_ops = &ov7740_subdev_internal_ops;
>> +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
>> +#endif
>> +
>> +#if defined(CONFIG_MEDIA_CONTROLLER)
>> +	ov7740->pad.flags = MEDIA_PAD_FL_SOURCE;
>> +	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
>> +	ret = media_entity_pads_init(&sd->entity, 1, &ov7740->pad);
>> +	if (ret)
>> +		return ret;
>> +#endif
>> +
>> +	ret = ov7740_set_power(ov7740, 1);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = ov7740_detect(ov7740);
>> +	if (ret)
>> +		goto error_detect;
>> +
>> +	mutex_init(&ov7740->mutex);
>> +
>> +	ret = ov7740_init_controls(ov7740);
>> +	if (ret)
>> +		goto error_init_controls;
>> +
>> +	v4l_info(client, "chip found @ 0x%02x (%s)\n",
>> +			client->addr << 1, client->adapter->name);
>> +
>> +	ov7740_init_default_format(ov7740);
> This doesn't yet address the issue. The sensor will be powered off just a
> few lines below, so the device state will be lost. You need to ensure the
> registers get programmed after the sensor is powered on and before
> streaming is started.
Right.
Thank you.

>
>> +
>> +	ov7740_get_default_format(sd, &ov7740->format);
>> +
>> +	ret = v4l2_async_register_subdev(sd);
>> +	if (ret)
>> +		goto error_async_register;
>> +
>> +	pm_runtime_set_active(&client->dev);
>> +	pm_runtime_enable(&client->dev);
>> +	pm_runtime_idle(&client->dev);
>> +
>> +	return 0;
>> +
>> +error_async_register:
>> +	v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
>> +error_init_controls:
>> +	ov7740_free_controls(ov7740);
>> +error_detect:
>> +	ov7740_set_power(ov7740, 0);
>> +	media_entity_cleanup(&ov7740->subdev.entity);
>> +
>> +	return ret;
>> +}
>> +
>> +static int ov7740_remove(struct i2c_client *client)
>> +{
>> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +
>> +	mutex_destroy(&ov7740->mutex);
>> +	v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
>> +#if defined(CONFIG_MEDIA_CONTROLLER)
>> +	media_entity_cleanup(&ov7740->subdev.entity);
>> +#endif
>> +	v4l2_async_unregister_subdev(sd);
>> +	ov7740_free_controls(ov7740);
>> +
>> +	pm_runtime_get_sync(&client->dev);
>> +	pm_runtime_disable(&client->dev);
>> +	pm_runtime_set_suspended(&client->dev);
>> +	pm_runtime_put_noidle(&client->dev);
>> +
>> +	ov7740_set_power(ov7740, 0);
>> +	return 0;
>> +}
>> +
>> +static int __maybe_unused ov7740_runtime_suspend(struct device *dev)
>> +{
>> +	struct i2c_client *client = to_i2c_client(dev);
>> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +
>> +	ov7740_set_power(ov7740, 0);
>> +
>> +	return 0;
>> +}
>> +
>> +static int __maybe_unused ov7740_runtime_resume(struct device *dev)
>> +{
>> +	struct i2c_client *client = to_i2c_client(dev);
>> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +
>> +	return ov7740_set_power(ov7740, 1);
>> +}
>> +
>> +static const struct i2c_device_id ov7740_id[] = {
>> +	{ "ov7740", 0 },
>> +	{ /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(i2c, ov7740_id);
>> +
>> +static const struct dev_pm_ops ov7740_pm_ops = {
>> +	SET_RUNTIME_PM_OPS(ov7740_runtime_suspend, ov7740_runtime_resume, NULL)
>> +};
>> +
>> +static const struct of_device_id ov7740_of_match[] = {
>> +	{.compatible = "ovti,ov7740", },
>> +	{ /* sentinel */ },
>> +};
>> +MODULE_DEVICE_TABLE(of, ov7740_of_match);
>> +
>> +static struct i2c_driver ov7740_i2c_driver = {
>> +	.driver = {
>> +		.name = "ov7740",
>> +		.pm = &ov7740_pm_ops,
>> +		.of_match_table = of_match_ptr(ov7740_of_match),
>> +	},
>> +	.probe    = ov7740_probe,
>> +	.remove   = ov7740_remove,
>> +	.id_table = ov7740_id,
>> +};
>> +module_i2c_driver(ov7740_i2c_driver);
>> +
>> +MODULE_DESCRIPTION("The V4L2 driver for Omnivision 7740 sensor");
>> +MODULE_AUTHOR("Songjun Wu <songjun.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>");
>> +MODULE_LICENSE("GPL v2");
>> -- 
>> 2.15.0
>>
Best Regards,
Wenyou Yang
--
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 v6 2/3] dmaeninge: xilinx_dma: Fix bug in multiple frame stores scenario in vdma
From: Appana Durga Kedareswara Rao @ 2017-12-06  4:11 UTC (permalink / raw)
  To: robh+dt@kernel.org, Mike Looijmans, mark.rutland@arm.com,
	dan.j.williams@intel.com, vinod.koul@intel.com,
	Michal Simek (michal.simek@xilinx.com), moritz.fischer@ettus.com,
	laurent.pinchart@ideasonboard.com, Jose.Abreu@synopsys.com,
	luis@debethencourt.com
  Cc: dmaengine@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <CY1PR02MB169299C7AA719D4CE56F328DDC3B0@CY1PR02MB1692.namprd02.prod.outlook.com>

Hi Mike Looijmans,

	Thanks for the review...
	Sorry for the long delay in the reply...
Please find comments inline... 

<Snip>
>On 14-01-17 06:35, Kedareswara rao Appana wrote:
>>  When VDMA is configured for more than one frame in the h/w.
>>  For example h/w is configured for n number of frames, user
>>  Submits n number of frames and triggered the DMA using issue_pending API.
>>
>>  In the current driver flow we are submitting one frame at a time,
>>  But we should submit all the n number of frames at one time
>>  As the h/w is configured for n number of frames.
>
>The hardware can always handle a single frame submission, by using the "park"
>bit. This would make a good "cyclic" implementation too (using vdma as
>framebuffer).
>
>It could also handle all cases for "k" frames where n%k==0 (n is a multiple of
>k) by simply replicating the frame pointers.

Agree with your comments will fix it in the next version.
Somehow didn't get enough time to send next version of the patch series.
Will modify the driver as per your comments and will post next version of the patch series at the earliest... 

Regards,
Kedar.


^ permalink raw reply

* Re: [PATCH v2 2/3] hwrng: exynos - add Samsung Exynos True RNG driver
From: PrasannaKumar Muralidharan @ 2017-12-06  3:10 UTC (permalink / raw)
  To: Łukasz Stelmach
  Cc: Andrew F. Davis, Rob Herring, Matt Mackall, Herbert Xu,
	Krzysztof Kozlowski, devicetree,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	linux-samsung-soc, open list, Marek Szyprowski,
	Bartlomiej Zolnierkiewicz
In-Reply-To: <20171127095804.7128-3-l.stelmach@samsung.com>

Hi Lukasz,

On 27 November 2017 at 15:28, Łukasz Stelmach <l.stelmach@samsung.com> wrote:
> Add support for True Random Number Generator found in Samsung Exynos
> 5250+ SoCs.
>
> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
> ---
>  MAINTAINERS                          |   7 +
>  drivers/char/hw_random/Kconfig       |  12 ++
>  drivers/char/hw_random/Makefile      |   1 +
>  drivers/char/hw_random/exynos-trng.c | 245 +++++++++++++++++++++++++++++++++++
>  4 files changed, 265 insertions(+)
>  create mode 100644 drivers/char/hw_random/exynos-trng.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2811a211632c..992074cca612 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11780,6 +11780,13 @@ S:     Maintained
>  F:     drivers/crypto/exynos-rng.c
>  F:     Documentation/devicetree/bindings/rng/samsung,exynos-rng4.txt
>
> +SAMSUNG EXYNOS TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER
> +M:     Łukasz Stelmach <l.stelmach@samsung.com>
> +L:     linux-samsung-soc@vger.kernel.org
> +S:     Maintained
> +F:     drivers/char/hw_random/exynos-trng.c
> +F:     Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.txt
> +
>  SAMSUNG FRAMEBUFFER DRIVER
>  M:     Jingoo Han <jingoohan1@gmail.com>
>  L:     linux-fbdev@vger.kernel.org
> diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
> index 95a031e9eced..292e6b36d493 100644
> --- a/drivers/char/hw_random/Kconfig
> +++ b/drivers/char/hw_random/Kconfig
> @@ -449,6 +449,18 @@ config HW_RANDOM_S390
>
>           If unsure, say Y.
>
> +config HW_RANDOM_EXYNOS
> +       tristate "Samsung Exynos True Random Number Generator support"
> +       depends on ARCH_EXYNOS || COMPILE_TEST
> +       default HW_RANDOM
> +       ---help---
> +         This driver provides support for the True Random Number
> +         Generator available in Exynos SoCs.
> +
> +         To compile this driver as a module, choose M here: the module
> +         will be called exynos-trng.
> +
> +         If unsure, say Y.
>  endif # HW_RANDOM
>
>  config UML_RANDOM
> diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
> index f3728d008fff..5595df97da7a 100644
> --- a/drivers/char/hw_random/Makefile
> +++ b/drivers/char/hw_random/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
>  obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o
>  n2-rng-y := n2-drv.o n2-asm.o
>  obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
> +obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-trng.o
>  obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
>  obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
>  obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += omap3-rom-rng.o
> diff --git a/drivers/char/hw_random/exynos-trng.c b/drivers/char/hw_random/exynos-trng.c
> new file mode 100644
> index 000000000000..91b2ddb249fa
> --- /dev/null
> +++ b/drivers/char/hw_random/exynos-trng.c
> @@ -0,0 +1,245 @@
> +/*
> + * RNG driver for Exynos TRNGs
> + *
> + * Author: Łukasz Stelmach <l.stelmach@samsung.com>
> + *
> + * Copyright 2017 (c) Samsung Electronics Software, Inc.
> + *
> + * Based on the Exynos PRNG driver drivers/crypto/exynos-rng by
> + * Krzysztof Kozłowski <krzk@kernel.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation;
> + *
> + * 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/crypto.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/hw_random.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +
> +#define EXYNOS_TRNG_CLKDIV         (0x0)
> +#define EXYNOS_TRNG_CTRL           (0x20)
> +#define EXYNOS_TRNG_POST_CTRL      (0x30)
> +#define EXYNOS_TRNG_ONLINE_CTRL    (0x40)
> +#define EXYNOS_TRNG_ONLINE_STAT    (0x44)
> +#define EXYNOS_TRNG_ONLINE_MAXCHI2 (0x48)
> +#define EXYNOS_TRNG_FIFO_CTRL      (0x50)
> +#define EXYNOS_TRNG_FIFO_0         (0x80)
> +#define EXYNOS_TRNG_FIFO_1         (0x84)
> +#define EXYNOS_TRNG_FIFO_2         (0x88)
> +#define EXYNOS_TRNG_FIFO_3         (0x8c)
> +#define EXYNOS_TRNG_FIFO_4         (0x90)
> +#define EXYNOS_TRNG_FIFO_5         (0x94)
> +#define EXYNOS_TRNG_FIFO_6         (0x98)
> +#define EXYNOS_TRNG_FIFO_7         (0x9c)
> +#define EXYNOS_TRNG_FIFO_LEN       (8)
> +#define EXYNOS_TRNG_CLOCK_RATE     (500000)
> +
> +#define TRNG_CTRL_RGNEN            BIT(31)
> +
> +struct exynos_trng_dev {
> +       struct device    *dev;
> +       void __iomem     *mem;
> +       struct clk       *clk;
> +       struct hwrng rng;
> +};
> +
> +static int exynos_trng_do_read(struct hwrng *rng, void *data, size_t max,
> +                              bool wait)
> +{
> +       struct exynos_trng_dev *trng;
> +       u32 val;
> +
> +       max = min_t(size_t, max, (EXYNOS_TRNG_FIFO_LEN * 4));
> +
> +       trng = (struct exynos_trng_dev *)rng->priv;
> +
> +       __raw_writel(max * 8, trng->mem + EXYNOS_TRNG_FIFO_CTRL);
> +       val = readl_poll_timeout(trng->mem + EXYNOS_TRNG_FIFO_CTRL, val,
> +                                val == 0, 200, 1000000);
> +       if (val < 0)
> +               return val;
> +
> +       memcpy_fromio(data, trng->mem + EXYNOS_TRNG_FIFO_0, max);
> +
> +       return max;
> +}
> +
> +static int exynos_trng_init(struct hwrng *rng)
> +{
> +       struct exynos_trng_dev *trng = (struct exynos_trng_dev *)rng->priv;
> +       unsigned long sss_rate;
> +       u32 val;
> +
> +       sss_rate = clk_get_rate(trng->clk);
> +
> +       /*
> +        * For most TRNG circuits the clock frequency of under 500 kHz
> +        * is safe.
> +        */
> +       val = sss_rate / (EXYNOS_TRNG_CLOCK_RATE * 2);
> +       if (val > 0x7fff) {
> +               dev_err(trng->dev, "clock divider too large: %d", val);
> +               return -ERANGE;
> +       }
> +       val = val << 1;
> +       __raw_writel(val, trng->mem + EXYNOS_TRNG_CLKDIV);
> +
> +       /* Enable the generator. */
> +       val = TRNG_CTRL_RGNEN;
> +       __raw_writel(val, trng->mem + EXYNOS_TRNG_CTRL);
> +
> +       /*
> +        * Disable post-processing. /dev/hwrng is supposed to deliver
> +        * unprocessed data.
> +        */
> +       __raw_writel(0, trng->mem + EXYNOS_TRNG_POST_CTRL);
> +
> +       return 0;
> +}
> +
> +static int exynos_trng_probe(struct platform_device *pdev)
> +{
> +       struct exynos_trng_dev *trng;
> +       struct resource *res;
> +       int ret = -ENOMEM;
> +
> +       trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
> +       if (!trng)
> +               return ret;
> +
> +       trng->rng.name = devm_kstrdup(&pdev->dev, dev_name(&pdev->dev),
> +                                     GFP_KERNEL);
> +       if (!trng->rng.name)
> +               return ret;
> +
> +       trng->rng.init = exynos_trng_init;
> +       trng->rng.read = exynos_trng_do_read;
> +       trng->rng.priv = (unsigned long) trng;
> +
> +       platform_set_drvdata(pdev, trng);
> +       trng->dev = &pdev->dev;
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       trng->mem = devm_ioremap_resource(&pdev->dev, res);
> +       if (IS_ERR(trng->mem)) {
> +               ret = PTR_ERR(trng->mem);
> +               dev_err(&pdev->dev, "Could not map IO resources.\n");
> +               goto err_ioremap;
> +       }
> +
> +       pm_runtime_enable(&pdev->dev);
> +       ret = pm_runtime_get_sync(&pdev->dev);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Could not get runtime PM.\n");
> +               goto err_pm_get;
> +       }
> +
> +       trng->clk = devm_clk_get(&pdev->dev, "secss");
> +       if (IS_ERR(trng->clk)) {
> +               ret = PTR_ERR(trng->clk);
> +               dev_err(&pdev->dev, "Could not get clock.\n");
> +               goto err_clock;
> +       }
> +
> +       ret = clk_prepare_enable(trng->clk);
> +       if (ret) {
> +               dev_err(&pdev->dev, "Could not enable the clk.\n");
> +               goto err_clock;
> +       }
> +
> +       ret = hwrng_register(&trng->rng);
> +       if (ret) {
> +               dev_err(&pdev->dev, "Could not register hwrng device.\n");
> +               goto err_register;
> +       }
> +
> +       dev_info(&pdev->dev, "Exynos True Random Number Generator.\n");
> +
> +       return 0;
> +
> +err_register:
> +       clk_disable_unprepare(trng->clk);
> +
> +err_clock:
> +       pm_runtime_put_sync(&pdev->dev);
> +
> +err_pm_get:
> +       pm_runtime_disable(&pdev->dev);
> +
> +err_ioremap:
> +       return ret;
> +}
> +
> +static int exynos_trng_remove(struct platform_device *pdev)
> +{
> +       struct exynos_trng_dev *trng =  platform_get_drvdata(pdev);
> +
> +       hwrng_unregister(&trng->rng);
> +       clk_disable_unprepare(trng->clk);
> +
> +       pm_runtime_put_sync(&pdev->dev);
> +       pm_runtime_disable(&pdev->dev);
> +
> +       return 0;
> +}
> +
> +static int __maybe_unused exynos_trng_suspend(struct device *dev)
> +{
> +       pm_runtime_put_sync(dev);
> +
> +       return 0;
> +}
> +
> +static int __maybe_unused exynos_trng_resume(struct device *dev)
> +{
> +       int ret;
> +
> +       ret = pm_runtime_get_sync(dev);
> +       if (ret < 0) {
> +               dev_err(dev, "Could not get runtime PM.\n");
> +               pm_runtime_put_noidle(dev);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(exynos_trng_pm_ops, exynos_trng_suspend,
> +                        exynos_trng_resume);
> +
> +static const struct of_device_id exynos_trng_dt_match[] = {
> +       {
> +               .compatible = "samsung,exynos5250-trng",
> +       },
> +       { },
> +};
> +MODULE_DEVICE_TABLE(of, exynos_rng_dt_match);
> +
> +static struct platform_driver exynos_trng_driver = {
> +       .driver = {
> +               .name = "exynos-trng",
> +               .pm = &exynos_trng_pm_ops,
> +               .of_match_table = exynos_trng_dt_match,
> +       },
> +       .probe = exynos_trng_probe,
> +       .remove = exynos_trng_remove,
> +};
> +
> +module_platform_driver(exynos_trng_driver);
> +MODULE_AUTHOR("Łukasz Stelmach");
> +MODULE_DESCRIPTION("H/W TRNG driver for Exynos chips");
> +MODULE_LICENSE("GPL");
> --
> 2.11.0
>

Reviewed-by: PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>

Regards,
PrasannaKumar

^ permalink raw reply

* [PATCH v2 3/3] ARM: dts: imx6sl-evk: Convert from fbdev to drm bindings
From: Marco Franchi @ 2017-12-06  2:53 UTC (permalink / raw)
  To: shawnguo-DgEjT+Ai2ygdnm+yROfE0A
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	festevam-Re5JQEeQqe8AvxtiuMwx3w, marcofrk-Re5JQEeQqe8AvxtiuMwx3w,
	Marco Franchi
In-Reply-To: <1512528784-29288-1-git-send-email-marcofrk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

It is preferred to use the panel compatible string rather than passing 
the LCD timing in the device tree.

So pass the "sii,43wvf1g" compatible string which describes the parallel 
LCD.

Also, pass the 'backlight' property as described in 
Documentation/devicetree/bindings/display/panel/simple-panel.txt

Signed-off-by: Marco Franchi <marco.franchi-3arQi8VN3Tc@public.gmane.org>
---
Changes since v1:
-change subject
-change message log
-includes into a set of patches
-fix regulator name and properties
 arch/arm/boot/dts/imx6sl-evk.dts | 48 ++++++++++++++++++++--------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts
index 645a460..a395de4 100644
--- a/arch/arm/boot/dts/imx6sl-evk.dts
+++ b/arch/arm/boot/dts/imx6sl-evk.dts
@@ -20,7 +20,7 @@
 		reg = <0x80000000 0x40000000>;
 	};
 
-	backlight {
+	backlight_display: backlight_display {
 		compatible = "pwm-backlight";
 		pwms = <&pwm1 0 5000000>;
 		brightness-levels = <0 4 8 16 32 64 128 255>;
@@ -82,6 +82,13 @@
 		enable-active-high;
 	};
 
+	reg_lcd_5v: regulator-lcd-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "lcd-5v0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
 	sound {
 		compatible = "fsl,imx6sl-evk-wm8962", "fsl,imx-audio-wm8962";
 		model = "wm8962-audio";
@@ -97,6 +104,19 @@
 		mux-int-port = <2>;
 		mux-ext-port = <3>;
 	};
+
+	panel {
+		compatible = "sii,43wvf1g";
+		backlight = <&backlight_display>;
+		dvdd-supply = <&reg_lcd_3v3>;
+		avdd-supply = <&reg_lcd_5v>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&display_out>;
+			};
+		};
+	};
 };
 
 &audmux {
@@ -535,31 +555,11 @@
 &lcdif {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_lcd>;
-	lcd-supply = <&reg_lcd_3v3>;
-	display = <&display0>;
 	status = "okay";
 
-	display0: display0 {
-		bits-per-pixel = <32>;
-		bus-width = <24>;
-
-		display-timings {
-			native-mode = <&timing0>;
-			timing0: timing0 {
-				clock-frequency = <33500000>;
-				hactive = <800>;
-				vactive = <480>;
-				hback-porch = <89>;
-				hfront-porch = <164>;
-				vback-porch = <23>;
-				vfront-porch = <10>;
-				hsync-len = <10>;
-				vsync-len = <10>;
-				hsync-active = <0>;
-				vsync-active = <0>;
-				de-active = <1>;
-				pixelclk-active = <0>;
-			};
+	port {
+		display_out: endpoint {
+			remote-endpoint = <&panel_in>;
 		};
 	};
 };
-- 
2.7.4

--
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

* [PATCH 2/3] ARM: dts: imx6sl-evk: Rearrange the regulators node
From: Marco Franchi @ 2017-12-06  2:53 UTC (permalink / raw)
  To: shawnguo
  Cc: robh+dt, linux-arm-kernel, linux-kernel, devicetree, festevam,
	marcofrk
In-Reply-To: <1512528784-29288-1-git-send-email-marcofrk@gmail.com>

It is not recommended to place regulators inside "simple-bus", so move 
them out.

The motivation for doing this is to make it easier to adding new 
regulators.

Signed-off-by: Marco Franchi <marcofrk@gmail.com>
---
 arch/arm/boot/dts/imx6sl-evk.dts | 85 +++++++++++++++++-----------------------
 1 file changed, 37 insertions(+), 48 deletions(-)

diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts
index 60600b4..645a460 100644
--- a/arch/arm/boot/dts/imx6sl-evk.dts
+++ b/arch/arm/boot/dts/imx6sl-evk.dts
@@ -39,58 +39,47 @@
 		};
 	};
 
-	regulators {
-		compatible = "simple-bus";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		reg_usb_otg1_vbus: regulator@0 {
-			compatible = "regulator-fixed";
-			reg = <0>;
-			regulator-name = "usb_otg1_vbus";
-			regulator-min-microvolt = <5000000>;
-			regulator-max-microvolt = <5000000>;
-			gpio = <&gpio4 0 0>;
-			enable-active-high;
-			vin-supply = <&swbst_reg>;
-		};
+	reg_usb_otg1_vbus: regulator-usb-otg1-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb_otg1_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio4 0 0>;
+		enable-active-high;
+		vin-supply = <&swbst_reg>;
+	};
 
-		reg_usb_otg2_vbus: regulator@1 {
-			compatible = "regulator-fixed";
-			reg = <1>;
-			regulator-name = "usb_otg2_vbus";
-			regulator-min-microvolt = <5000000>;
-			regulator-max-microvolt = <5000000>;
-			gpio = <&gpio4 2 0>;
-			enable-active-high;
-			vin-supply = <&swbst_reg>;
-		};
+	reg_usb_otg2_vbus: regulator-usb-otg2-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb_otg2_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio4 2 0>;
+		enable-active-high;
+		vin-supply = <&swbst_reg>;
+	};
 
-		reg_aud3v: regulator@2 {
-			compatible = "regulator-fixed";
-			reg = <2>;
-			regulator-name = "wm8962-supply-3v15";
-			regulator-min-microvolt = <3150000>;
-			regulator-max-microvolt = <3150000>;
-			regulator-boot-on;
-		};
+	reg_aud3v: regulator-aud3v {
+		compatible = "regulator-fixed";
+		regulator-name = "wm8962-supply-3v15";
+		regulator-min-microvolt = <3150000>;
+		regulator-max-microvolt = <3150000>;
+		regulator-boot-on;
+	};
 
-		reg_aud4v: regulator@3 {
-			compatible = "regulator-fixed";
-			reg = <3>;
-			regulator-name = "wm8962-supply-4v2";
-			regulator-min-microvolt = <4325000>;
-			regulator-max-microvolt = <4325000>;
-			regulator-boot-on;
-		};
+	reg_aud4v: regulator-aud4v {
+		compatible = "regulator-fixed";
+		regulator-name = "wm8962-supply-4v2";
+		regulator-min-microvolt = <4325000>;
+		regulator-max-microvolt = <4325000>;
+		regulator-boot-on;
+	};
 
-		reg_lcd_3v3: regulator@4 {
-			compatible = "regulator-fixed";
-			reg = <4>;
-			regulator-name = "lcd-3v3";
-			gpio = <&gpio4 3 0>;
-			enable-active-high;
-		};
+	reg_lcd_3v3: regulator-lcd-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "lcd-3v3";
+		gpio = <&gpio4 3 0>;
+		enable-active-high;
 	};
 
 	sound {
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 1/3] ARM: dts: imx6sx-sdb: Convert from fbdev to drm bindings
From: Marco Franchi @ 2017-12-06  2:53 UTC (permalink / raw)
  To: shawnguo-DgEjT+Ai2ygdnm+yROfE0A
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	festevam-Re5JQEeQqe8AvxtiuMwx3w, marcofrk-Re5JQEeQqe8AvxtiuMwx3w

It is preferred to use the panel compatible string rather than passing
the LCD timing in the device tree.

So pass the "sii,43wvf1g" compatible string, which describes the parallel 
LCD.

Also pass the 'backlight' property as described in
Documentation/devicetree/bindings/display/panel/simple-panel.txt

Signed-off-by: Marco Franchi <marcofrk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
Changes since v1:
-change subject
-change message log
-includes into a set of patches
-rebase to linux-next
-fix regulator name and properties
 arch/arm/boot/dts/imx6sx-sdb.dtsi | 48 +++++++++++++++++++--------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/arch/arm/boot/dts/imx6sx-sdb.dtsi b/arch/arm/boot/dts/imx6sx-sdb.dtsi
index d57a41c..d35aa85 100644
--- a/arch/arm/boot/dts/imx6sx-sdb.dtsi
+++ b/arch/arm/boot/dts/imx6sx-sdb.dtsi
@@ -24,7 +24,7 @@
 		reg = <0x80000000 0x40000000>;
 	};
 
-	backlight {
+	backlight_display: backlight-display {
 		compatible = "pwm-backlight";
 		pwms = <&pwm3 0 5000000>;
 		brightness-levels = <0 4 8 16 32 64 128 255>;
@@ -129,6 +129,13 @@
 		enable-active-high;
 	};
 
+	reg_lcd_5v: regulator-lcd-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "lcd-5v0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
 	sound {
 		compatible = "fsl,imx6sx-sdb-wm8962", "fsl,imx-audio-wm8962";
 		model = "wm8962-audio";
@@ -144,6 +151,19 @@
 		mux-int-port = <2>;
 		mux-ext-port = <6>;
 	};
+
+	panel {
+		compatible = "sii,43wvf1g";
+		backlight = <&backlight_display>;
+		dvdd-supply = <&reg_lcd_3v3>;
+		avdd-supply = <&reg_lcd_5v>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&display_out>;
+			};
+		};
+	};
 };
 
 &audmux {
@@ -221,31 +241,11 @@
 &lcdif1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_lcd>;
-	lcd-supply = <&reg_lcd_3v3>;
-	display = <&display0>;
 	status = "okay";
 
-	display0: display0 {
-		bits-per-pixel = <16>;
-		bus-width = <24>;
-
-		display-timings {
-			native-mode = <&timing0>;
-			timing0: timing0 {
-				clock-frequency = <33500000>;
-				hactive = <800>;
-				vactive = <480>;
-				hback-porch = <89>;
-				hfront-porch = <164>;
-				vback-porch = <23>;
-				vfront-porch = <10>;
-				hsync-len = <10>;
-				vsync-len = <10>;
-				hsync-active = <0>;
-				vsync-active = <0>;
-				de-active = <1>;
-				pixelclk-active = <0>;
-			};
+	port {
+		display_out: endpoint {
+			remote-endpoint = <&panel_in>;
 		};
 	};
 };
-- 
2.7.4

--
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

* Re: [PATCH v3 0/2] of: overlay: Fix of_overlay_apply() error path
From: Frank Rowand @ 2017-12-06  2:40 UTC (permalink / raw)
  To: Geert Uytterhoeven, Pantelis Antoniou, Rob Herring
  Cc: Colin King, Dan Carpenter, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1512487623-30450-1-git-send-email-geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org>

On 12/05/17 10:27, Geert Uytterhoeven wrote:
> 	Hi Pantelis, Rob, Frank,
> 
> Here's a replacement for commit bd80e2555c5c9d45 ("of: overlay: Fix
> cleanup order in of_overlay_apply()"), which was applied by Rob, and
> dropped later.
> 
> The first patch fixes the memory leak reported by Colin.
> The second patch is a replacement for the bad dropped commit, and
> depends on the first patch for proper cleanup.
> 
> All OF unittests pass.
> 
> Thanks!
> 
> Geert Uytterhoeven (2):
>   of: overlay: Fix memory leak in of_overlay_apply() error path
>   of: overlay: Fix (un)locking in of_overlay_apply()
> 
>  drivers/of/overlay.c | 31 +++++++++++++------------------
>  1 file changed, 13 insertions(+), 18 deletions(-)
> 

Thank you, the code is much improved by these patches.

Reviewed-by: Frank Rowand <frank.rowand-7U/KSKJipcs@public.gmane.org>
--
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

* [PATCH v7 2/2] media: i2c: Add the ov7740 image sensor driver
From: Wenyou Yang @ 2017-12-06  2:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Mark Rutland
  Cc: linux-kernel, Nicolas Ferre, devicetree, Sakari Ailus,
	Jonathan Corbet, Hans Verkuil, linux-arm-kernel,
	Linux Media Mailing List, Wenyou Yang, Songjun Wu
In-Reply-To: <20171206022343.31104-1-wenyou.yang@microchip.com>

The ov7740 (color) image sensor is a high performance VGA CMOS
image snesor, which supports for output formats: RAW RGB and YUV
and image sizes: VGA, and QVGA, CIF and any size smaller.

Signed-off-by: Songjun Wu <songjun.wu@microchip.com>
Signed-off-by: Wenyou Yang <wenyou.yang@microchip.com>
---

Changes in v7:
 - Fix the wrong handle of default register configuration.
 - Add the missed assignment of ov7740->frmsize.

Changes in v6:
 - Remove unnecessary #include <linux/init>.
 - Remove unnecessary comments and extra newline.
 - Add const for some structures.
 - Add the check of the return value from regmap_write().
 - Simplify the calling of __v4l2_ctrl_handler_setup().
 - Add the default format initialization function.
 - Integrate the set_power() and enable/disable the clock into
   one function.

Changes in v5:
 - Squash the driver and MAINTAINERS entry patches to one.
 - Precede the driver patch with the bindings patch.

Changes in v4:
 - Assign 'val' a initial value to avoid warning: 'val' may be
   used uninitialized.
 - Rename REG_REG15 to avoid warning: "REG_REG15" redefined.

Changes in v3:
 - Put the MAINTAINERS change to a separate patch.

Changes in v2:
 - Split off the bindings into a separate patch.
 - Add a new entry to the MAINTAINERS file.

 MAINTAINERS                |    8 +
 drivers/media/i2c/Kconfig  |    8 +
 drivers/media/i2c/Makefile |    1 +
 drivers/media/i2c/ov7740.c | 1234 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1251 insertions(+)
 create mode 100644 drivers/media/i2c/ov7740.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 7a52a66aa991..1de965009b13 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10053,6 +10053,14 @@ S:	Maintained
 F:	drivers/media/i2c/ov7670.c
 F:	Documentation/devicetree/bindings/media/i2c/ov7670.txt
 
+OMNIVISION OV7740 SENSOR DRIVER
+M:	Wenyou Yang <wenyou.yang@microchip.com>
+L:	linux-media@vger.kernel.org
+T:	git git://linuxtv.org/media_tree.git
+S:	Maintained
+F:	drivers/media/i2c/ov7740.c
+F:	Documentation/devicetree/bindings/media/i2c/ov7740.txt
+
 ONENAND FLASH DRIVER
 M:	Kyungmin Park <kyungmin.park@samsung.com>
 L:	linux-mtd@lists.infradead.org
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index cb5d7ff82915..00b1c4c031d4 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -665,6 +665,14 @@ config VIDEO_OV7670
 	  OV7670 VGA camera.  It currently only works with the M88ALP01
 	  controller.
 
+config VIDEO_OV7740
+	tristate "OmniVision OV7740 sensor support"
+	depends on I2C && VIDEO_V4L2
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This is a Video4Linux2 sensor-level driver for the OmniVision
+	  OV7740 VGA camera sensor.
+
 config VIDEO_OV9650
 	tristate "OmniVision OV9650/OV9652 sensor support"
 	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 548a9efce966..9b19ec7fcaf4 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_VIDEO_OV5670) += ov5670.o
 obj-$(CONFIG_VIDEO_OV6650) += ov6650.o
 obj-$(CONFIG_VIDEO_OV7640) += ov7640.o
 obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
 obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
 obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
 obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
new file mode 100644
index 000000000000..26b56a627377
--- /dev/null
+++ b/drivers/media/i2c/ov7740.c
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (c) 2017 Microchip 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.
+ *
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-subdev.h>
+
+#define REG_OUTSIZE_LSB 0x34
+
+/* OV7740 register tables */
+#define REG_GAIN	0x00	/* Gain lower 8 bits (rest in vref) */
+#define REG_BGAIN	0x01	/* blue gain */
+#define REG_RGAIN	0x02	/* red gain */
+#define REG_GGAIN	0x03	/* green gain */
+#define REG_REG04	0x04	/* analog setting, dont change*/
+#define REG_BAVG	0x05	/* b channel average */
+#define REG_GAVG	0x06	/* g channel average */
+#define REG_RAVG	0x07	/* r channel average */
+
+#define REG_REG0C	0x0C	/* filp enable */
+#define REG0C_IMG_FLIP		0x80
+#define REG0C_IMG_MIRROR	0x40
+
+#define REG_REG0E	0x0E	/* blc line */
+#define REG_HAEC	0x0F	/* auto exposure cntrl */
+#define REG_AEC		0x10	/* auto exposure cntrl */
+
+#define REG_CLK		0x11	/* Clock control */
+#define REG_REG55	0x55	/* Clock PLL DIV/PreDiv */
+
+#define REG_REG12	0x12
+
+#define REG_REG13	0x13	/* auto/manual AGC, AEC, Write Balance*/
+#define REG13_AEC_EN	0x01
+#define REG13_AGC_EN	0x04
+
+#define REG_REG14	0x14
+#define REG_CTRL15	0x15
+#define REG15_GAIN_MSB	0x03
+
+#define REG_REG16	0x16
+
+#define REG_MIDH	0x1C	/* manufacture id byte */
+#define REG_MIDL	0x1D	/* manufacture id byre */
+#define REG_PIDH	0x0A	/* Product ID MSB */
+#define REG_PIDL	0x0B	/* Product ID LSB */
+
+#define REG_84		0x84	/* lots of stuff */
+#define REG_REG38	0x38	/* sub-addr */
+
+#define REG_AHSTART	0x17	/* Horiz start high bits */
+#define REG_AHSIZE	0x18
+#define REG_AVSTART	0x19	/* Vert start high bits */
+#define REG_AVSIZE	0x1A
+#define REG_PSHFT	0x1b	/* Pixel delay after HREF */
+
+#define REG_HOUTSIZE	0x31
+#define REG_VOUTSIZE	0x32
+#define REG_HVSIZEOFF	0x33
+#define REG_REG34	0x34	/* DSP output size H/V LSB*/
+
+#define REG_ISP_CTRL00	0x80
+#define ISPCTRL00_AWB_EN	0x10
+#define ISPCTRL00_AWB_GAIN_EN	0x04
+
+#define	REG_YGAIN	0xE2	/* ygain for contrast control */
+
+#define	REG_YBRIGHT	  0xE3
+#define	REG_SGNSET	  0xE4
+#define	SGNSET_YBRIGHT_MASK	  0x08
+
+#define REG_USAT	0xDD
+#define REG_VSAT	0xDE
+
+
+struct ov7740 {
+	struct v4l2_subdev subdev;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	struct media_pad pad;
+#endif
+	struct v4l2_mbus_framefmt format;
+	const struct ov7740_pixfmt *fmt;  /* Current format */
+	const struct ov7740_framesize *frmsize;
+	struct regmap *regmap;
+	struct clk *xvclk;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct {
+		/* gain cluster */
+		struct v4l2_ctrl *auto_gain;
+		struct v4l2_ctrl *gain;
+	};
+	struct {
+		struct v4l2_ctrl *auto_wb;
+		struct v4l2_ctrl *blue_balance;
+		struct v4l2_ctrl *red_balance;
+	};
+	struct {
+		struct v4l2_ctrl *hflip;
+		struct v4l2_ctrl *vflip;
+	};
+	struct {
+		/* exposure cluster */
+		struct v4l2_ctrl *auto_exposure;
+		struct v4l2_ctrl *exposure;
+	};
+	struct {
+		/* saturation/hue cluster */
+		struct v4l2_ctrl *saturation;
+		struct v4l2_ctrl *hue;
+	};
+	struct v4l2_ctrl *brightness;
+	struct v4l2_ctrl *contrast;
+
+	struct mutex mutex;	/* To serialize asynchronus callbacks */
+	bool streaming;		/* Streaming on/off */
+
+	struct gpio_desc *resetb_gpio;
+	struct gpio_desc *pwdn_gpio;
+};
+
+struct ov7740_pixfmt {
+	u32 mbus_code;
+	enum v4l2_colorspace colorspace;
+	const struct reg_sequence *regs;
+	u32 reg_num;
+};
+
+struct ov7740_framesize {
+	u16 width;
+	u16 height;
+	const struct reg_sequence *regs;
+	u32 reg_num;
+};
+
+static const struct reg_sequence ov7740_vga[] = {
+	{0x55, 0x40},
+	{0x11, 0x02},
+
+	{0xd5, 0x10},
+	{0x0c, 0x12},
+	{0x0d, 0x34},
+	{0x17, 0x25},
+	{0x18, 0xa0},
+	{0x19, 0x03},
+	{0x1a, 0xf0},
+	{0x1b, 0x89},
+	{0x22, 0x03},
+	{0x29, 0x18},
+	{0x2b, 0xf8},
+	{0x2c, 0x01},
+	{REG_HOUTSIZE, 0xa0},
+	{REG_VOUTSIZE, 0xf0},
+	{0x33, 0xc4},
+	{REG_OUTSIZE_LSB, 0x0},
+	{0x35, 0x05},
+	{0x04, 0x60},
+	{0x27, 0x80},
+	{0x3d, 0x0f},
+	{0x3e, 0x80},
+	{0x3f, 0x40},
+	{0x40, 0x7f},
+	{0x41, 0x6a},
+	{0x42, 0x29},
+	{0x44, 0x22},
+	{0x45, 0x41},
+	{0x47, 0x02},
+	{0x49, 0x64},
+	{0x4a, 0xa1},
+	{0x4b, 0x40},
+	{0x4c, 0x1a},
+	{0x4d, 0x50},
+	{0x4e, 0x13},
+	{0x64, 0x00},
+	{0x67, 0x88},
+	{0x68, 0x1a},
+
+	{0x14, 0x28},
+	{0x24, 0x3c},
+	{0x25, 0x30},
+	{0x26, 0x72},
+	{0x50, 0x97},
+	{0x51, 0x1f},
+	{0x52, 0x00},
+	{0x53, 0x00},
+	{0x20, 0x00},
+	{0x21, 0xcf},
+	{0x50, 0x4b},
+	{0x38, 0x14},
+	{0xe9, 0x00},
+	{0x56, 0x55},
+	{0x57, 0xff},
+	{0x58, 0xff},
+	{0x59, 0xff},
+	{0x5f, 0x04},
+	{0xec, 0x00},
+	{0x13, 0xff},
+
+	{0x81, 0x3f},
+	{0x82, 0x32},
+	{0x38, 0x11},
+	{0x84, 0x70},
+	{0x85, 0x00},
+	{0x86, 0x03},
+	{0x87, 0x01},
+	{0x88, 0x05},
+	{0x89, 0x30},
+	{0x8d, 0x30},
+	{0x8f, 0x85},
+	{0x93, 0x30},
+	{0x95, 0x85},
+	{0x99, 0x30},
+	{0x9b, 0x85},
+
+	{0x9c, 0x08},
+	{0x9d, 0x12},
+	{0x9e, 0x23},
+	{0x9f, 0x45},
+	{0xa0, 0x55},
+	{0xa1, 0x64},
+	{0xa2, 0x72},
+	{0xa3, 0x7f},
+	{0xa4, 0x8b},
+	{0xa5, 0x95},
+	{0xa6, 0xa7},
+	{0xa7, 0xb5},
+	{0xa8, 0xcb},
+	{0xa9, 0xdd},
+	{0xaa, 0xec},
+	{0xab, 0x1a},
+
+	{0xce, 0x78},
+	{0xcf, 0x6e},
+	{0xd0, 0x0a},
+	{0xd1, 0x0c},
+	{0xd2, 0x84},
+	{0xd3, 0x90},
+	{0xd4, 0x1e},
+
+	{0x5a, 0x24},
+	{0x5b, 0x1f},
+	{0x5c, 0x88},
+	{0x5d, 0x60},
+
+	{0xac, 0x6e},
+	{0xbe, 0xff},
+	{0xbf, 0x00},
+
+	{0x0f, 0x1d},
+	{0x0f, 0x1f},
+};
+
+static const struct ov7740_framesize ov7740_framesizes[] = {
+	{
+		.width		= VGA_WIDTH,
+		.height		= VGA_HEIGHT,
+		.regs		= ov7740_vga,
+		.reg_num	= ARRAY_SIZE(ov7740_vga),
+	},
+};
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov7740_get_register(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_register *reg)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+	struct regmap *regmap = ov7740->regmap;
+	unsigned int val = 0;
+	int ret;
+
+	ret = regmap_read(regmap, reg->reg & 0xff, &val);
+	reg->val = val;
+	reg->size = 1;
+
+	return 0;
+}
+
+static int ov7740_set_register(struct v4l2_subdev *sd,
+			       const struct v4l2_dbg_register *reg)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+	struct regmap *regmap = ov7740->regmap;
+
+	regmap_write(regmap, reg->reg & 0xff, reg->val & 0xff);
+
+	return 0;
+}
+#endif
+
+static int ov7740_set_power(struct ov7740 *ov7740, int on)
+{
+	int ret;
+
+	if (on) {
+		ret = clk_prepare_enable(ov7740->xvclk);
+		if (ret)
+			return ret;
+
+		if (ov7740->pwdn_gpio)
+			gpiod_direction_output(ov7740->pwdn_gpio, 0);
+
+		if (ov7740->resetb_gpio) {
+			gpiod_set_value(ov7740->resetb_gpio, 1);
+			usleep_range(500, 1000);
+			gpiod_set_value(ov7740->resetb_gpio, 0);
+			usleep_range(3000, 5000);
+		}
+	} else {
+		clk_disable_unprepare(ov7740->xvclk);
+
+		if (ov7740->pwdn_gpio)
+			gpiod_direction_output(ov7740->pwdn_gpio, 0);
+	}
+
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops ov7740_subdev_core_ops = {
+	.log_status = v4l2_ctrl_subdev_log_status,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = ov7740_get_register,
+	.s_register = ov7740_set_register,
+#endif
+	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static int ov7740_set_white_balance(struct ov7740 *ov7740, int awb)
+{
+	struct regmap *regmap = ov7740->regmap;
+	unsigned int value;
+	int ret;
+
+	ret = regmap_read(regmap, REG_ISP_CTRL00, &value);
+	if (!ret) {
+		if (awb)
+			value |= (ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN);
+		else
+			value &= ~(ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN);
+		ret = regmap_write(regmap, REG_ISP_CTRL00, value);
+		if (ret)
+			return ret;
+	}
+
+	if (!awb) {
+		ret = regmap_write(regmap, REG_BGAIN,
+				   ov7740->blue_balance->val);
+		if (ret)
+			return ret;
+
+		ret = regmap_write(regmap, REG_RGAIN, ov7740->red_balance->val);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int ov7740_set_saturation(struct regmap *regmap, int value)
+{
+	int ret;
+
+	ret = regmap_write(regmap, REG_USAT, (unsigned char)value);
+	if (ret)
+		return ret;
+
+	return regmap_write(regmap, REG_VSAT, (unsigned char)value);
+}
+
+static int ov7740_set_gain(struct regmap *regmap, int value)
+{
+	int ret;
+
+	ret = regmap_write(regmap, REG_GAIN, value & 0xff);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(regmap, REG_CTRL15,
+				 REG15_GAIN_MSB, (value >> 8) & 0x3);
+	if (!ret)
+		ret = regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0);
+
+	return ret;
+}
+
+static int ov7740_set_autogain(struct regmap *regmap, int value)
+{
+	unsigned int reg;
+	int ret;
+
+	ret = regmap_read(regmap, REG_REG13, &reg);
+	if (ret)
+		return ret;
+	if (value)
+		reg |= REG13_AGC_EN;
+	else
+		reg &= ~REG13_AGC_EN;
+	return regmap_write(regmap, REG_REG13, reg);
+}
+
+static int ov7740_set_brightness(struct regmap *regmap, int value)
+{
+	/* Turn off AEC/AGC */
+	regmap_update_bits(regmap, REG_REG13, REG13_AEC_EN, 0);
+	regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0);
+
+	if (value >= 0) {
+		regmap_write(regmap, REG_YBRIGHT, (unsigned char)value);
+		regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 0);
+	} else{
+		regmap_write(regmap, REG_YBRIGHT, (unsigned char)(-value));
+		regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 1);
+	}
+
+	return 0;
+}
+
+static int ov7740_set_contrast(struct regmap *regmap, int value)
+{
+	return regmap_write(regmap, REG_YGAIN, (unsigned char)value);
+}
+
+static int ov7740_get_gain(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl)
+{
+	struct regmap *regmap = ov7740->regmap;
+	unsigned int value0, value1;
+	int ret;
+
+	if (!ctrl->val)
+		return 0;
+
+	ret = regmap_read(regmap, REG_GAIN, &value0);
+	if (ret)
+		return ret;
+	ret = regmap_read(regmap, REG_CTRL15, &value1);
+	if (ret)
+		return ret;
+
+	ov7740->gain->val = (value1 << 8) | (value0 & 0xff);
+
+	return 0;
+}
+
+static int ov7740_set_exp(struct regmap *regmap, int value)
+{
+	int ret;
+
+	/* Turn off AEC/AGC */
+	ret = regmap_update_bits(regmap, REG_REG13,
+				 REG13_AEC_EN | REG13_AGC_EN, 0);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(regmap, REG_AEC, (unsigned char)value);
+	if (ret)
+		return ret;
+
+	return regmap_write(regmap, REG_HAEC, (unsigned char)(value >> 8));
+}
+
+static int ov7740_set_autoexp(struct regmap *regmap,
+			      enum v4l2_exposure_auto_type value)
+{
+	unsigned int reg;
+	int ret;
+
+	ret = regmap_read(regmap, REG_REG13, &reg);
+	if (!ret) {
+		if (value == V4L2_EXPOSURE_AUTO)
+			reg |= (REG13_AEC_EN | REG13_AGC_EN);
+		else
+			reg &= ~(REG13_AEC_EN | REG13_AGC_EN);
+		ret = regmap_write(regmap, REG_REG13, reg);
+	}
+
+	return ret;
+}
+
+
+static int ov7740_get_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov7740 *ov7740 = container_of(ctrl->handler,
+					     struct ov7740, ctrl_handler);
+	int ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTOGAIN:
+		ret = ov7740_get_gain(ov7740, ctrl);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov7740 *ov7740 = container_of(ctrl->handler,
+					     struct ov7740, ctrl_handler);
+	struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev);
+	struct regmap *regmap = ov7740->regmap;
+	int ret;
+	u8 val = 0;
+
+	if (pm_runtime_get_if_in_use(&client->dev) <= 0)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		ret = ov7740_set_white_balance(ov7740, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		ret = ov7740_set_saturation(regmap, ctrl->val);
+		break;
+	case V4L2_CID_BRIGHTNESS:
+		ret = ov7740_set_brightness(regmap, ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		ret = ov7740_set_contrast(regmap, ctrl->val);
+		break;
+	case V4L2_CID_VFLIP:
+		ret = regmap_update_bits(regmap, REG_REG0C,
+					 REG0C_IMG_FLIP, val);
+		break;
+	case V4L2_CID_HFLIP:
+		val = ctrl->val ? REG0C_IMG_MIRROR : 0x00;
+		ret = regmap_update_bits(regmap, REG_REG0C,
+					 REG0C_IMG_MIRROR, val);
+		break;
+	case V4L2_CID_AUTOGAIN:
+		if (!ctrl->val)
+			return ov7740_set_gain(regmap, ov7740->gain->val);
+
+		ret = ov7740_set_autogain(regmap, ctrl->val);
+		break;
+
+	case V4L2_CID_EXPOSURE_AUTO:
+		if (ctrl->val == V4L2_EXPOSURE_MANUAL)
+			return ov7740_set_exp(regmap, ov7740->exposure->val);
+
+		ret = ov7740_set_autoexp(regmap, ctrl->val);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	pm_runtime_put(&client->dev);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops ov7740_ctrl_ops = {
+	.g_volatile_ctrl = ov7740_get_volatile_ctrl,
+	.s_ctrl = ov7740_set_ctrl,
+};
+
+static int ov7740_start_streaming(struct ov7740 *ov7740)
+{
+	int ret;
+
+	if (ov7740->fmt) {
+		ret = regmap_multi_reg_write(ov7740->regmap,
+					     ov7740->fmt->regs,
+					     ov7740->fmt->reg_num);
+		if (ret)
+			return ret;
+	}
+
+	if (ov7740->frmsize) {
+		ret = regmap_multi_reg_write(ov7740->regmap,
+					     ov7740->frmsize->regs,
+					     ov7740->frmsize->reg_num);
+		if (ret)
+			return ret;
+	}
+
+	return __v4l2_ctrl_handler_setup(ov7740->subdev.ctrl_handler);
+}
+
+static int ov7740_set_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = 0;
+
+	mutex_lock(&ov7740->mutex);
+	if (ov7740->streaming == enable) {
+		mutex_unlock(&ov7740->mutex);
+		return 0;
+	}
+
+	if (enable) {
+		ret = pm_runtime_get_sync(&client->dev);
+		if (ret < 0) {
+			pm_runtime_put_noidle(&client->dev);
+			goto err_unlock;
+		}
+
+		ret = ov7740_start_streaming(ov7740);
+		if (ret)
+			goto err_rpm_put;
+	} else {
+		pm_runtime_put(&client->dev);
+	}
+
+	ov7740->streaming = enable;
+
+	mutex_unlock(&ov7740->mutex);
+	return ret;
+
+err_rpm_put:
+	pm_runtime_put(&client->dev);
+err_unlock:
+	mutex_unlock(&ov7740->mutex);
+	return ret;
+}
+
+static int ov7740_get_parm(struct v4l2_subdev *sd,
+			   struct v4l2_streamparm *parms)
+{
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+	struct v4l2_fract *tpf = &cp->timeperframe;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	memset(cp, 0, sizeof(struct v4l2_captureparm));
+	cp->capability = V4L2_CAP_TIMEPERFRAME;
+
+	tpf->numerator = 1;
+	tpf->denominator = 60;
+
+	return 0;
+}
+
+static int ov7740_set_parm(struct v4l2_subdev *sd,
+			   struct v4l2_streamparm *parms)
+{
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+	struct v4l2_fract *tpf = &cp->timeperframe;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (cp->extendedmode != 0)
+		return -EINVAL;
+
+	cp->capability = V4L2_CAP_TIMEPERFRAME;
+
+	tpf->numerator = 1;
+	tpf->denominator = 60;
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {
+	.s_stream = ov7740_set_stream,
+	.s_parm = ov7740_set_parm,
+	.g_parm = ov7740_get_parm,
+};
+
+static const struct reg_sequence ov7740_format_yuyv[] = {
+	{0x12, 0x00},
+	{0x36, 0x3f},
+	{0x80, 0x7f},
+	{0x83, 0x01},
+};
+
+static const struct reg_sequence ov7740_format_bggr8[] = {
+	{0x36, 0x2f},
+	{0x80, 0x01},
+	{0x83, 0x04},
+};
+
+static const struct ov7740_pixfmt ov7740_formats[] = {
+	{
+		.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.regs = ov7740_format_yuyv,
+		.reg_num = ARRAY_SIZE(ov7740_format_yuyv),
+	},
+	{
+		.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.regs = ov7740_format_bggr8,
+		.reg_num = ARRAY_SIZE(ov7740_format_bggr8),
+	}
+};
+#define N_OV7740_FMTS ARRAY_SIZE(ov7740_formats)
+
+static int ov7740_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad || code->index >= N_OV7740_FMTS)
+		return -EINVAL;
+
+	code->code = ov7740_formats[code->index].mbus_code;
+
+	return 0;
+}
+
+static int ov7740_enum_frame_interval(struct v4l2_subdev *sd,
+				struct v4l2_subdev_pad_config *cfg,
+				struct v4l2_subdev_frame_interval_enum *fie)
+{
+	if (fie->pad)
+		return -EINVAL;
+
+	if (fie->index >= 1)
+		return -EINVAL;
+
+	if ((fie->width != VGA_WIDTH) || (fie->height != VGA_HEIGHT))
+		return -EINVAL;
+
+	fie->interval.numerator = 1;
+	fie->interval.denominator = 60;
+
+	return 0;
+}
+
+static int ov7740_enum_frame_size(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->pad)
+		return -EINVAL;
+
+	if (fse->index > 0)
+		return -EINVAL;
+
+	fse->min_width = fse->max_width = VGA_WIDTH;
+	fse->min_height = fse->max_height = VGA_HEIGHT;
+
+	return 0;
+}
+
+static int ov7740_try_fmt_internal(struct v4l2_subdev *sd,
+				   struct v4l2_mbus_framefmt *fmt,
+				   const struct ov7740_pixfmt **ret_fmt,
+				   const struct ov7740_framesize **ret_frmsize)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+	const struct ov7740_framesize *fsize = &ov7740_framesizes[0];
+	int index, i;
+
+	for (index = 0; index < N_OV7740_FMTS; index++) {
+		if (ov7740_formats[index].mbus_code == fmt->code)
+			break;
+	}
+	if (index >= N_OV7740_FMTS) {
+		/* default to first format */
+		index = 0;
+		fmt->code = ov7740_formats[0].mbus_code;
+	}
+	if (ret_fmt != NULL)
+		*ret_fmt = ov7740_formats + index;
+
+	for (i = 0; i < ARRAY_SIZE(ov7740_framesizes); i++) {
+		if ((fsize->width >= fmt->width) &&
+		    (fsize->height >= fmt->height)) {
+			fmt->width = fsize->width;
+			fmt->height = fsize->height;
+			break;
+		}
+
+		fsize++;
+	}
+
+	if (ret_frmsize != NULL)
+		*ret_frmsize = fsize;
+
+	fmt->field = V4L2_FIELD_NONE;
+	fmt->colorspace = ov7740_formats[index].colorspace;
+
+	ov7740->format = *fmt;
+
+	return 0;
+}
+
+static int ov7740_set_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_format *format)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+	const struct ov7740_pixfmt *ovfmt;
+	const struct ov7740_framesize *fsize;
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+	struct v4l2_mbus_framefmt *mbus_fmt;
+#endif
+	int ret;
+
+	mutex_lock(&ov7740->mutex);
+	if (format->pad) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+		ret = ov7740_try_fmt_internal(sd, &format->format, NULL, NULL);
+		if (ret)
+			goto error;
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+		mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+		*mbus_fmt = format->format;
+
+		mutex_unlock(&ov7740->mutex);
+		return 0;
+#else
+		ret = -ENOTTY;
+		goto error;
+#endif
+	}
+
+	ret = ov7740_try_fmt_internal(sd, &format->format, &ovfmt, &fsize);
+	if (ret)
+		goto error;
+
+	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		regmap_multi_reg_write(ov7740->regmap,
+				       ovfmt->regs, ovfmt->reg_num);
+
+		regmap_multi_reg_write(ov7740->regmap,
+				       fsize->regs, fsize->reg_num);
+	}
+
+	ov7740->fmt = ovfmt;
+	ov7740->frmsize = fsize;
+
+	mutex_unlock(&ov7740->mutex);
+	return 0;
+
+error:
+	mutex_unlock(&ov7740->mutex);
+	return ret;
+}
+
+static int ov7740_get_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_format *format)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+	struct v4l2_mbus_framefmt *mbus_fmt;
+#endif
+	int ret = 0;
+
+	mutex_lock(&ov7740->mutex);
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+		mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+		format->format = *mbus_fmt;
+		ret = 0;
+#else
+		ret = -ENOTTY;
+#endif
+	} else {
+		format->format = ov7740->format;
+	}
+	mutex_unlock(&ov7740->mutex);
+
+	return ret;
+}
+
+static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = {
+	.enum_frame_interval = ov7740_enum_frame_interval,
+	.enum_frame_size = ov7740_enum_frame_size,
+	.enum_mbus_code = ov7740_enum_mbus_code,
+	.get_fmt = ov7740_get_fmt,
+	.set_fmt = ov7740_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov7740_subdev_ops = {
+	.core	= &ov7740_subdev_core_ops,
+	.video	= &ov7740_subdev_video_ops,
+	.pad	= &ov7740_subdev_pad_ops,
+};
+
+static void ov7740_get_default_format(struct v4l2_subdev *sd,
+				      struct v4l2_mbus_framefmt *format)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+
+	format->width = ov7740->frmsize->width;
+	format->height = ov7740->frmsize->height;
+	format->colorspace = ov7740->fmt->colorspace;
+	format->code = ov7740->fmt->mbus_code;
+	format->field = V4L2_FIELD_NONE;
+}
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+	struct v4l2_mbus_framefmt *format =
+				v4l2_subdev_get_try_format(sd, fh->pad, 0);
+
+	mutex_lock(&ov7740->mutex);
+	ov7740_get_default_format(sd, format);
+	mutex_unlock(&ov7740->mutex);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops ov7740_subdev_internal_ops = {
+	.open = ov7740_open,
+};
+#endif
+
+static int ov7740_probe_dt(struct i2c_client *client,
+			   struct ov7740 *ov7740)
+{
+	ov7740->resetb_gpio = devm_gpiod_get_optional(&client->dev, "reset",
+			GPIOD_OUT_HIGH);
+	if (IS_ERR(ov7740->resetb_gpio)) {
+		dev_info(&client->dev, "can't get %s GPIO\n", "reset");
+		return PTR_ERR(ov7740->resetb_gpio);
+	}
+
+	ov7740->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
+			GPIOD_OUT_LOW);
+	if (IS_ERR(ov7740->pwdn_gpio)) {
+		dev_info(&client->dev, "can't get %s GPIO\n", "powerdown");
+		return PTR_ERR(ov7740->pwdn_gpio);
+	}
+
+	return 0;
+}
+
+static int ov7740_detect(struct ov7740 *ov7740)
+{
+	struct regmap *regmap = ov7740->regmap;
+	unsigned int midh, midl, pidh, pidl;
+	int ret;
+
+	ret = regmap_read(regmap, REG_MIDH, &midh);
+	if (ret)
+		return ret;
+	if (midh != 0x7f)
+		return -ENODEV;
+
+	ret = regmap_read(regmap, REG_MIDL, &midl);
+	if (ret)
+		return ret;
+	if (midl != 0xa2)
+		return -ENODEV;
+
+	ret = regmap_read(regmap, REG_PIDH, &pidh);
+	if (ret)
+		return ret;
+	if (pidh != 0x77)
+		return -ENODEV;
+
+	ret = regmap_read(regmap, REG_PIDL, &pidl);
+	if (ret)
+		return ret;
+	if ((pidl != 0x40) && (pidl != 0x41) && (pidl != 0x42))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int ov7740_init_controls(struct ov7740 *ov7740)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev);
+	struct v4l2_ctrl_handler *ctrl_hdlr = &ov7740->ctrl_handler;
+	int ret;
+
+	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 2);
+	if (ret < 0)
+		return ret;
+
+	ctrl_hdlr->lock = &ov7740->mutex;
+	ov7740->auto_wb = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					  V4L2_CID_AUTO_WHITE_BALANCE,
+					  0, 1, 1, 1);
+	ov7740->blue_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					       V4L2_CID_BLUE_BALANCE,
+					       0, 0xff, 1, 0x80);
+	ov7740->red_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					      V4L2_CID_RED_BALANCE,
+					      0, 0xff, 1, 0x80);
+
+	ov7740->brightness = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					     V4L2_CID_BRIGHTNESS,
+					     -255, 255, 1, 0);
+	ov7740->contrast = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					   V4L2_CID_CONTRAST,
+					   0, 127, 1, 0x20);
+	ov7740->saturation = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+			  V4L2_CID_SATURATION, 0, 256, 1, 0x80);
+	ov7740->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					V4L2_CID_HFLIP, 0, 1, 1, 0);
+	ov7740->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					V4L2_CID_VFLIP, 0, 1, 1, 0);
+	ov7740->gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+				       V4L2_CID_GAIN, 0, 1023, 1, 500);
+	ov7740->auto_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					    V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	ov7740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					   V4L2_CID_EXPOSURE, 0, 65535, 1, 500);
+	ov7740->auto_exposure = v4l2_ctrl_new_std_menu(ctrl_hdlr,
+					&ov7740_ctrl_ops,
+					V4L2_CID_EXPOSURE_AUTO,
+					V4L2_EXPOSURE_MANUAL, 0,
+					V4L2_EXPOSURE_AUTO);
+
+	ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	ov7740->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+	v4l2_ctrl_auto_cluster(3, &ov7740->auto_wb, 0, false);
+	v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true);
+	v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure,
+			       V4L2_EXPOSURE_MANUAL, false);
+	v4l2_ctrl_cluster(2, &ov7740->hflip);
+
+	ret = v4l2_ctrl_handler_setup(ctrl_hdlr);
+	if (ret) {
+		dev_err(&client->dev, "%s control init failed (%d)\n",
+			__func__, ret);
+		goto error;
+	}
+
+	ov7740->subdev.ctrl_handler = ctrl_hdlr;
+	return 0;
+
+error:
+	v4l2_ctrl_handler_free(ctrl_hdlr);
+	mutex_destroy(&ov7740->mutex);
+	return ret;
+}
+
+static void ov7740_free_controls(struct ov7740 *ov7740)
+{
+	v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
+	mutex_destroy(&ov7740->mutex);
+}
+
+#define OV7740_MAX_REGISTER     0xff
+static const struct regmap_config ov7740_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= OV7740_MAX_REGISTER,
+};
+
+static int ov7740_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct ov7740 *ov7740;
+	struct v4l2_subdev *sd;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_err(&client->dev,
+			"OV7740: I2C-Adapter doesn't support SMBUS\n");
+		return -EIO;
+	}
+
+	ov7740 = devm_kzalloc(&client->dev, sizeof(*ov7740), GFP_KERNEL);
+	if (!ov7740)
+		return -ENOMEM;
+
+	ov7740->xvclk = devm_clk_get(&client->dev, "xvclk");
+	if (IS_ERR(ov7740->xvclk)) {
+		ret = PTR_ERR(ov7740->xvclk);
+		dev_err(&client->dev,
+			"OV7740: fail to get xvclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = ov7740_probe_dt(client, ov7740);
+	if (ret)
+		return ret;
+
+	ov7740->regmap = devm_regmap_init_i2c(client, &ov7740_regmap_config);
+	if (IS_ERR(ov7740->regmap)) {
+		ret = PTR_ERR(ov7740->regmap);
+		dev_err(&client->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	sd = &ov7740->subdev;
+	client->flags |= I2C_CLIENT_SCCB;
+	v4l2_i2c_subdev_init(sd, client, &ov7740_subdev_ops);
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+	sd->internal_ops = &ov7740_subdev_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+#endif
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	ov7740->pad.flags = MEDIA_PAD_FL_SOURCE;
+	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+	ret = media_entity_pads_init(&sd->entity, 1, &ov7740->pad);
+	if (ret)
+		return ret;
+#endif
+
+	ret = ov7740_set_power(ov7740, 1);
+	if (ret)
+		return ret;
+
+	ret = ov7740_detect(ov7740);
+	if (ret)
+		goto error_detect;
+
+	mutex_init(&ov7740->mutex);
+
+	ret = ov7740_init_controls(ov7740);
+	if (ret)
+		goto error_init_controls;
+
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	ov7740->fmt = &ov7740_formats[0];
+	ov7740->frmsize = &ov7740_framesizes[0];
+
+	ov7740_get_default_format(sd, &ov7740->format);
+
+	ret = v4l2_async_register_subdev(sd);
+	if (ret)
+		goto error_async_register;
+
+	pm_runtime_set_active(&client->dev);
+	pm_runtime_enable(&client->dev);
+	pm_runtime_idle(&client->dev);
+
+	return 0;
+
+error_async_register:
+	v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
+error_init_controls:
+	ov7740_free_controls(ov7740);
+error_detect:
+	ov7740_set_power(ov7740, 0);
+	media_entity_cleanup(&ov7740->subdev.entity);
+
+	return ret;
+}
+
+static int ov7740_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+
+	mutex_destroy(&ov7740->mutex);
+	v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	media_entity_cleanup(&ov7740->subdev.entity);
+#endif
+	v4l2_async_unregister_subdev(sd);
+	ov7740_free_controls(ov7740);
+
+	pm_runtime_get_sync(&client->dev);
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+	pm_runtime_put_noidle(&client->dev);
+
+	ov7740_set_power(ov7740, 0);
+	return 0;
+}
+
+static int __maybe_unused ov7740_runtime_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+
+	ov7740_set_power(ov7740, 0);
+
+	return 0;
+}
+
+static int __maybe_unused ov7740_runtime_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+
+	return ov7740_set_power(ov7740, 1);
+}
+
+static const struct i2c_device_id ov7740_id[] = {
+	{ "ov7740", 0 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, ov7740_id);
+
+static const struct dev_pm_ops ov7740_pm_ops = {
+	SET_RUNTIME_PM_OPS(ov7740_runtime_suspend, ov7740_runtime_resume, NULL)
+};
+
+static const struct of_device_id ov7740_of_match[] = {
+	{.compatible = "ovti,ov7740", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ov7740_of_match);
+
+static struct i2c_driver ov7740_i2c_driver = {
+	.driver = {
+		.name = "ov7740",
+		.pm = &ov7740_pm_ops,
+		.of_match_table = of_match_ptr(ov7740_of_match),
+	},
+	.probe    = ov7740_probe,
+	.remove   = ov7740_remove,
+	.id_table = ov7740_id,
+};
+module_i2c_driver(ov7740_i2c_driver);
+
+MODULE_DESCRIPTION("The V4L2 driver for Omnivision 7740 sensor");
+MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.15.0

^ permalink raw reply related

* [PATCH v7 1/2] media: ov7740: Document device tree bindings
From: Wenyou Yang @ 2017-12-06  2:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Mark Rutland
  Cc: linux-kernel, Nicolas Ferre, devicetree, Sakari Ailus,
	Jonathan Corbet, Hans Verkuil, linux-arm-kernel,
	Linux Media Mailing List, Wenyou Yang
In-Reply-To: <20171206022343.31104-1-wenyou.yang@microchip.com>

Add the device tree binding documentation for the ov7740 sensor driver.

Signed-off-by: Wenyou Yang <wenyou.yang@microchip.com>
Acked-by: Rob Herring <robh@kernel.org>
---

Changes in v7:
 - Add Acked-by tag.

Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3:
 - Explicitly document the "remote-endpoint" property.

Changes in v2: None

 .../devicetree/bindings/media/i2c/ov7740.txt       | 47 ++++++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/i2c/ov7740.txt

diff --git a/Documentation/devicetree/bindings/media/i2c/ov7740.txt b/Documentation/devicetree/bindings/media/i2c/ov7740.txt
new file mode 100644
index 000000000000..af781c3a5f0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ov7740.txt
@@ -0,0 +1,47 @@
+* Omnivision OV7740 CMOS image sensor
+
+The Omnivision OV7740 image sensor supports multiple output image
+size, such as VGA, and QVGA, CIF and any size smaller. It also
+supports the RAW RGB and YUV output formats.
+
+The common video interfaces bindings (see video-interfaces.txt) should
+be used to specify link to the image data receiver. The OV7740 device
+node should contain one 'port' child node with an 'endpoint' subnode.
+
+Required Properties:
+- compatible:	"ovti,ov7740".
+- reg:		I2C slave address of the sensor.
+- clocks:	Reference to the xvclk input clock.
+- clock-names:	"xvclk".
+
+Optional Properties:
+- reset-gpios: Rreference to the GPIO connected to the reset_b pin,
+  if any. Active low with pull-ip resistor.
+- powerdown-gpios: Reference to the GPIO connected to the pwdn pin,
+  if any. Active high with pull-down resistor.
+
+Endpoint node mandatory properties:
+- remote-endpoint: A phandle to the bus receiver's endpoint node.
+
+Example:
+
+	i2c1: i2c@fc028000 {
+		ov7740: camera@21 {
+			compatible = "ovti,ov7740";
+			reg = <0x21>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>;
+			clocks = <&isc>;
+			clock-names = "xvclk";
+			assigned-clocks = <&isc>;
+			assigned-clock-rates = <24000000>;
+			reset-gpios = <&pioA 43 GPIO_ACTIVE_LOW>;
+			powerdown-gpios = <&pioA 44 GPIO_ACTIVE_HIGH>;
+
+			port {
+				ov7740_0: endpoint {
+					remote-endpoint = <&isc_0>;
+				};
+			};
+		};
+	};
-- 
2.15.0

^ permalink raw reply related

* [PATCH v7 0/2] media: ov7740: Add a V4L2 sensor-level driver
From: Wenyou Yang @ 2017-12-06  2:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Mark Rutland
  Cc: linux-kernel, Nicolas Ferre, devicetree, Sakari Ailus,
	Jonathan Corbet, Hans Verkuil, linux-arm-kernel,
	Linux Media Mailing List, Wenyou Yang

Add a Video4Linux2 sensor-level driver for the OmniVision OV7740
VGA camera image sensor.

Changes in v7:
 - Add Acked-by tag.
 - Fix the wrong handle of default register configuration.
 - Add the missed assignment of ov7740->frmsize.

Changes in v6:
 - Remove unnecessary #include <linux/init>.
 - Remove unnecessary comments and extra newline.
 - Add const for some structures.
 - Add the check of the return value from regmap_write().
 - Simplify the calling of __v4l2_ctrl_handler_setup().
 - Add the default format initialization function.
 - Integrate the set_power() and enable/disable the clock into
   one function.

Changes in v5:
 - Squash the driver and MAINTAINERS entry patches to one.
 - Precede the driver patch with the bindings patch.

Changes in v4:
 - Assign 'val' a initial value to avoid warning: 'val' may be
   used uninitialized.
 - Rename REG_REG15 to avoid warning: "REG_REG15" redefined.

Changes in v3:
 - Explicitly document the "remote-endpoint" property.
 - Put the MAINTAINERS change to a separate patch.

Changes in v2:
 - Split off the bindings into a separate patch.
 - Add a new entry to the MAINTAINERS file.

Wenyou Yang (2):
  media: ov7740: Document device tree bindings
  media: i2c: Add the ov7740 image sensor driver

 .../devicetree/bindings/media/i2c/ov7740.txt       |   47 +
 MAINTAINERS                                        |    8 +
 drivers/media/i2c/Kconfig                          |    8 +
 drivers/media/i2c/Makefile                         |    1 +
 drivers/media/i2c/ov7740.c                         | 1234 ++++++++++++++++++++
 5 files changed, 1298 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/i2c/ov7740.txt
 create mode 100644 drivers/media/i2c/ov7740.c

-- 
2.15.0

^ permalink raw reply

* RE: [PATCH net-next v3 4/4] net: fec: add phy_reset_after_clk_enable() support
From: Andy Duan @ 2017-12-06  1:50 UTC (permalink / raw)
  To: Richard Leitner, robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	mark.rutland-5wv7dgnIgG8@public.gmane.org,
	andrew-g2DYL2Zd6BY@public.gmane.org,
	f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
  Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org,
	geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org,
	baruch-NswTu9S1W3P6gbPvEgmw2w@public.gmane.org,
	david.wu-TNX95d0MmH7DzftRWevZcw@public.gmane.org,
	lukma-ynQEQJNshbs@public.gmane.org,
	netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	richard.leitner-WcANXNA0UjBBDgjK7y7TUQ@public.gmane.org
In-Reply-To: <20171205132600.13796-5-dev-M/VWbR8SM2SsTnJN9+BGXg@public.gmane.org>

From: Richard Leitner <dev-M/VWbR8SM2SsTnJN9+BGXg@public.gmane.org> Sent: Tuesday, December 05, 2017 9:26 PM
>Some PHYs (for example the SMSC LAN8710/LAN8720) doesn't allow turning
>the refclk on and off again during operation (according to their datasheet).
>Nonetheless exactly this behaviour was introduced for power saving reasons
>by commit e8fcfcd5684a ("net: fec: optimize the clock management to save
>power").
>Therefore add support for the phy_reset_after_clk_enable function from
>phylib to mitigate this issue.
>
>Generally speaking this issue is only relevant if the ref clk for the PHY is
>generated by the SoC and therefore the PHY is configured to "REF_CLK In
>Mode". In our specific case (PCB) this problem does occur at about every 10th
>to 50th POR of an LAN8710 connected to an i.MX6SOLO SoC. The typical
>symptom of this problem is a "swinging" ethernet link.
>Similar issues were reported by users of the NXP forum:
>	https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F
>%2Fcommunity.nxp.com%2Fthread%2F389902&data=02%7C01%7Cfugang.du
>an%40nxp.com%7C7f9fee272fc44662c2a108d53be3d1ee%7C686ea1d3bc2b4c6
>fa92cd99c5c301635%7C0%7C0%7C636480772022331090&sdata=7RdUsoWVWu
>o1nM5zKwLt7%2F6U3dxgDJtBDGlQCUWC6IM%3D&reserved=0
>	https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F
>%2Fcommunity.nxp.com%2Fmessage%2F309354&data=02%7C01%7Cfugang.d
>uan%40nxp.com%7C7f9fee272fc44662c2a108d53be3d1ee%7C686ea1d3bc2b4
>c6fa92cd99c5c301635%7C0%7C0%7C636480772022331090&sdata=D56KilGWD3
>kLABxc0yOI%2B44Y%2FhLfrGtdAvupCEyvI%2BI%3D&reserved=0
>With this patch applied the issue didn't occur for at least a few hundret PORs
>of our board.
>
>Fixes: e8fcfcd5684a ("net: fec: optimize the clock management to save
>power")
>Signed-off-by: Richard Leitner <richard.leitner-WcANXNA0UjBBDgjK7y7TUQ@public.gmane.org>
>---
> drivers/net/ethernet/freescale/fec_main.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
>diff --git a/drivers/net/ethernet/freescale/fec_main.c
>b/drivers/net/ethernet/freescale/fec_main.c
>index 610573855213..8c3d0fb7db20 100644
>--- a/drivers/net/ethernet/freescale/fec_main.c
>+++ b/drivers/net/ethernet/freescale/fec_main.c
>@@ -1862,6 +1862,8 @@ static int fec_enet_clk_enable(struct net_device
>*ndev, bool enable)
> 		ret = clk_prepare_enable(fep->clk_ref);
> 		if (ret)
> 			goto failed_clk_ref;
>+
>+		phy_reset_after_clk_enable(ndev->phydev);
> 	} else {
> 		clk_disable_unprepare(fep->clk_ahb);
> 		clk_disable_unprepare(fep->clk_enet_out);
>@@ -2860,6 +2862,11 @@ fec_enet_open(struct net_device *ndev)
> 	if (ret)
> 		goto err_enet_mii_probe;
>
>+	/* reset phy if needed here, due to the fact this is the first time we
>+	 * have the net_device to phy_driver link
>+	 */
>+	phy_reset_after_clk_enable(ndev->phydev);
>+

The patch series look better.
But why does it need to reset phy here since phy already is hard reset after clock enable.


> 	if (fep->quirks & FEC_QUIRK_ERR006687)
> 		imx6q_cpuidle_fec_irqs_used();
>
>--
>2.11.0
--
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 v3 3/3] arm64: dts: meson-axg: add clock DT info for Meson AXG SoC
From: Stephen Boyd @ 2017-12-06  1:00 UTC (permalink / raw)
  To: Jerome Brunet
  Cc: Yixun Lan, Neil Armstrong, Kevin Hilman, Rob Herring,
	Mark Rutland, Michael Turquette, Carlo Caione, Qiufang Dai,
	linux-amlogic, devicetree, linux-clk, linux-arm-kernel,
	linux-kernel
In-Reply-To: <1512147583.12869.10.camel@baylibre.com>

On 12/01, Jerome Brunet wrote:
> On Fri, 2017-12-01 at 08:34 -0800, Stephen Boyd wrote:
> > On 11/30, Yixun Lan wrote:
> > > Hi Stephen
> > > 
> > > On 11/30/17 03:35, Stephen Boyd wrote:
> > > > 
> > > > Maybe just call the node "bus@ff63c000"?
> > > > 
> > > 
> > > isn't this just a name? what's the benefits to change?
> > > personally, I tend to keep it this way, because it's better map to the
> > > data sheet
> > > 
> > > we also has 'aobus', 'cbus' scattered there..
> > 
> > Per the ePAPR node names are supposed to be generic, like disk,
> > cpu, display-controller, gpu, etc. I've never heard of a hiubus,
> > so probably it's some vendor specific thing? We have the phandle
> > anyway so it's not like we're losing much information here.
> 
> Stephen, there is a lot of busses on platform. We can't just call them all
> 'bus'.
> I don't get the problem with this name.
> We are re-using the name from the datasheet here, no fancy invention. It seems
> to be quite common. 
> 

Ok. I'm not the maintainer of the DTS so no worries from me. I'm
just pointing out that the ePAPR says that node names should be
generic, and 'hiubus' doesn't sound generic to me. If it matches
some datasheet then I suppose that's good, but probably that sort
of distinction should have gone into the compatible string
instead of the node name.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* Re: [RFC PATCH 1/3] dt-bindings: pinctrl: sunxi: document new generic binding
From: André Przywara @ 2017-12-06  0:55 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Thierry Reding, Maxime Ripard, Chen-Yu Tsai,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Linux ARM, Arnd Bergmann, Icenowy Zheng,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
In-Reply-To: <CACRpkdZ70a7Vk1QPFhkms6ucWmSH6rOUD9_J0h=NjhK+vfXNAA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

Hi Linus,

thanks for the reply!

On 01/12/17 09:56, Linus Walleij wrote:
> On Fri, Nov 24, 2017 at 6:19 PM, Andre Przywara <andre.przywara-5wv7dgnIgG8@public.gmane.org> wrote:
> 
>> Conceptually I consider the DT being
>> part of the firmware,
> 
> As it is a subset of open firmware it is obviously firmware.
> 
>> so one trust level above the kernel.
> 
> We are several kernel developers who don't trust firmware one
> bit. Several disasters in ACPI has made me ever more convinced
> that firmware should be trusted less than kernel code.

I know what you mean, check commit acd316248205 ;-)

But in the Allwinner case all the firmware is open source, and even
controlled by the community (ATF & U-Boot). This is even more true for
the DT. Allwinner came up with their own DT, but since it uses
completely non-standard bindings, we don't use it at all.

So I don't consider firmware this dark, evil and unhackable blob that
many people see in it. Instead it is a good opportunity to separate very
tedious machine-specific parts from the kernel (think of PSCI).

> But this is all very academic.

I agree!

>>> Also, device tree bindings are not documentation for how to write a
>>> driver. They are not a replacement for hardware documentation. Nobody
>>> should be expected to be able to write an OS driver solely based on a
>>> device tree binding. Device tree bindings are more of a configuration
>>> interface specification for OS drivers.
>>
>> Yes, but together with the hardware docs you should be able to write a
>> driver. And here you can't, because you are missing the strings. So a
>> BSD developer has to look at Linux code.
> 
> This is a fair point. It appears in several drivers.
> 
> BSD or even Windows (would they use DT) would have to sit in the
> back seat just like Linux has been doing for years when it comes
> to the hopeless Windowsisms in the x86 BIOSes. I suspect some
> Windows on ARM is already experiencing this, but in the ACPI world,
> where, incidentally, the servers were being deployed for Linux first
> and Windows had to follow their example. I bet they have been
> swearing a lot in Redmond about that.

On the other hand a lot of the ACPI tables have been either taken from
x86 or designed also with Windows in mind. And frankly, my sympathy for
MS is quite limited in this respect ;-)

> In general it's one of these areas where we can not be utopian about the
> hardware descriptions, just fail gracefully in different ways.
> 
> I usually try to keep the IETF motto "rough consensus and running
> code" in mind. I don't know if it helps in this discussion though.
> 
>>> So that's about 40% of the kernel image. Code really is no good without
>>> data to process.
>>
>> But how much of this is SoC specific configuration data? How much is it
>> in x86? Yes, historically we had and have a lot of configuration data in
>> ARM kernels. But that doesn't mean that we have to continue with this or
>> even increase the share.
> 
> What people have been doing is trying to have better Kconfig setups
> and compile it out by doing kernel modules. It is a bit hopeless with
> pin controllers: almost all of them have to be built in. And if they come
> with a lot of data, yeah there you have a real good point.
> 
> It would be sad if the ARMv7 multiboot or Aarch64 kernel just grows
> so that we can't use it but have to go back to shipping board-specific
> kernels with a huge bunch of stuff compiled out.
> 
> I was hoping Moore's law would save us here :/
> 
> An option that has been discussed is better used of  __initdata
> and similar tags, especially with built-in drivers. Sadly, this is
> hurt by another snag: the compiler or linker file or whatever it is,
> is preventing us from discarding any strings from the kernel.
> And pin controllers tend to stack up a lot of these.
> 
> This is really sucky and something we should solve in general.
> I'm not smart enough to tackle any of these problems myself, just
> to see them and "Oh that's bad. Very bad."

I am sure one can find clever hac^Wsolutions for this problem, but I was
wondering if a new approach - like putting the per machine data actually
in DT - isn't the smarter way.
Hence my suggestion with this driver: we *need* the DT anyway to assign
pins to devices, so why not just add the few bytes *there*, which allows
us to have a more or less "data-less" DT driver?

>From what I learned the pinctrl subsystem seems to predates the ARM DT
endeavor, so many design decisions probably didn't consider DT as a
possible solution in the first way. And this is fine, because this is
how it was back then. But it doesn't mean it has to stay this way. And I
carefully thought of solving this problem without alienating existing
users and developers - by keeping the driver and staying compatible with
the existing binding and the DTs.

>>> The majority of the improvements over the years have been achieved by
>>> moving drivers out of arch/arm and moving board files to DT. The goal
>>> was never to get rid of all data.
>>
>> Sure, not all data. But if we have the relatively easy opportunity to
>> avoid further addition of data, we should do it, I believe.
>> This significantly reduces the amount of kernel code we need to add to
>> support new SoCs.
> 
> This is the core of your argument as I perceive it: get rid of data
> from the kernel, because it is growing wild.

Yes, this, but also to avoid replicating data in other DT consumers. I
very much like the idea of the DT describing the hardware, but I am a
bit afraid we loose many good opportunities by treating the DT more like
a "Linux config file" or an external Linux board file.
So I wanted to propose a way where we simplify DT usage in other
systems, while still keeping the Linux driver intact.

> It is a valid cause. Just
> has to be weighed with other stuff, like maintainability, debuggability,
> maintainers viewpoint. ...

So to keep Maxime happy I actually designed this "driver" more like a
shim: to generate the table the current driver expects from the DT, and
actually not touching the existing driver at all.
So maintainability should actually be less of a concern: the driver will
just work with whatever one throws at it from the DT side, without
requiring frequent changes or additions.
In the moment we still need to write, review and merge *data* files for
each new SoC. And as I mentioned before, Allwinner decided to push for
new, slightly different chips every few months, so there will be more to
come. With at least the pinctrl driver out of the way we have one
problem less to worry about.

Cheers,
Andre.
--
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 v4] usb: xhci: allow imod-interval to be configurable
From: Adam Wallis @ 2017-12-05 23:50 UTC (permalink / raw)
  To: Mathias Nyman, Chunfeng Yun
  Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA, Mathias Nyman,
	Greg Kroah-Hartman, timur-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-usb-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
	linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Matthias Brugger,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <f5ca26d2-9432-2ae3-7501-5b3dcf1e1486-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>

Rob,

On 12/5/2017 3:48 AM, Mathias Nyman wrote:
> On 05.12.2017 04:54, Adam Wallis wrote:
>> On 12/4/2017 9:15 PM, Chunfeng Yun wrote:
>>> On Mon, 2017-12-04 at 09:27 -0500, Adam Wallis wrote:
>>>> The xHCI driver currently has the IMOD set to 160, which
[..]
> 
> If Rob Acks this version I'll apply it and remove that blank line.
> 
> -Mathias
> 

Let me know if you have any other issues with this patch, otherwise with your
ACK, we are done.

Thanks

Adam

> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


-- 
Adam Wallis
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.
--
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 v4 02/10] pinctrl: axp209: add pinctrl features
From: kbuild test robot @ 2017-12-05 23:21 UTC (permalink / raw)
  Cc: kbuild-all, linus.walleij, robh+dt, mark.rutland, wens, linux,
	maxime.ripard, lee.jones, linux-gpio, devicetree, linux-kernel,
	linux-arm-kernel, thomas.petazzoni, linux-sunxi, Quentin Schulz
In-Reply-To: <71c9da94df2a5938cb8c092e40f8e36eec0b01c3.1512135804.git-series.quentin.schulz@free-electrons.com>

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

Hi Quentin,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on pinctrl/devel]
[also build test ERROR on v4.15-rc2 next-20171205]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Quentin-Schulz/pinctrl-move-gpio-axp209-to-pinctrl/20171204-050707
base:   https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git devel
config: i386-randconfig-h1-12060258 (attached as .config)
compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

>> drivers//pinctrl/pinctrl-axp209.c:290:21: error: 'pinconf_generic_dt_node_to_map_group' undeclared here (not in a function)
     .dt_node_to_map  = pinconf_generic_dt_node_to_map_group,
                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers//pinctrl/pinctrl-axp209.c:291:18: error: 'pinconf_generic_dt_free_map' undeclared here (not in a function)
     .dt_free_map  = pinconf_generic_dt_free_map,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~

vim +/pinconf_generic_dt_node_to_map_group +290 drivers//pinctrl/pinctrl-axp209.c

   288	
   289	static const struct pinctrl_ops axp20x_pctrl_ops = {
 > 290		.dt_node_to_map		= pinconf_generic_dt_node_to_map_group,
 > 291		.dt_free_map		= pinconf_generic_dt_free_map,
   292		.get_groups_count	= axp20x_groups_cnt,
   293		.get_group_name		= axp20x_group_name,
   294		.get_group_pins		= axp20x_group_pins,
   295	};
   296	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 28831 bytes --]

^ permalink raw reply

* Re: [PATCH v2 1/2] of: overlay: Fix memory leak in of_overlay_apply() error path
From: Frank Rowand @ 2017-12-05 22:47 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Geert Uytterhoeven, Pantelis Antoniou, Rob Herring, Colin King,
	Dan Carpenter, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAMuHMdX__gY+TG2Pe-8FZSGCG1m8yLYYszrFHDPVHK5JJsnxqA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On 12/05/17 08:58, Geert Uytterhoeven wrote:
> Hi Frank,
> 
> On Tue, Dec 5, 2017 at 2:45 PM, Frank Rowand <frowand.list-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> On 12/05/17 03:01, Geert Uytterhoeven wrote:
>>> On Tue, Dec 5, 2017 at 3:07 AM, Frank Rowand <frowand.list-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>>>> Also, the previous version of the patch, and the discussion around the resulting
>>>> bug make me think that I should not have moved 'kfree(ovcs)' into
>>>> free_overlay_changeset(), because that kfree is then not very visible in the
>>>> error path of of_overlay_apply().  Could you remove 'kfree(ovcs)' from
>>>> free_overlay_changeset(), and instead call it immediately after each call
>>>> to free_overlay_changeset()?
>>>
>>> Actually I like that free_overlay_changeset() takes care of the deallocation,
>>> especially in light of the kojectification op top from bbb-overlays, which
>>> means you cannot just call kfree(ovcs) anymore (I know this won't go upstream
>>> anytime soon, but I need overlay configfs for my development and testing).
>>
>> OK, knowing that kobjectification is being considered I am willing to leave the
>> kfree(ovcs) where it is for now.
>>
>>> Perhaps the allocation of ovcs should be moved into free_overlay_changeset(),
>>
>>                                           I think this ^^^^^^^^^^^^^^^^^^^^^^^
>> is a typo, and you meant init_overlay_changeset().
> 
> Yes it is.
> 
>>> and the latter being renamed to alloc_overlay_changeset()?
>>> That way allocation and freeing become symmetrical.
>>> It would move the allocation under the mutexes, though.
>>
>> I considered moving the kzalloc() into init_overlay_changeset() when I
>> created it, but decided not to because the type of the first argument of
>> init_overlay_changeset() would change from
>>    struct overlay_changeset *
>> to
>>    struct overlay_changeset **,
>> and usage of ovcs would become _slightly_ more ugly and complex in
>> init_overlay_changeset().
> 
> I would let alloc_overlay_changeset() return struct overlay_changeset *
> instead.
> 
> If you care about why it failed, it can return ERR_PTR(error) instead of
> NULL ;-)

Yes, it should continue to return the error reason.

Thanks,

Frank


> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                 -- Linus Torvalds
> 

--
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

* [PATCH v1 6/6] ARM: dts: imx7s: add usb hsic phy domain
From: tyler @ 2017-12-05 22:27 UTC (permalink / raw)
  To: shawnguo, festevam, kernel
  Cc: robh+dt, mark.rutland, linux-arm-kernel, devicetree, linux-kernel,
	fabio.estevam, Tyler Baker
In-Reply-To: <20171205222707.11302-1-tyler@opensourcefoundries.com>

From: Tyler Baker <tyler@opensourcefoundries.com>

The GPCv2 driver should control the MIPI, PCIe,
and USB HSIC PHY regulators. Add the USB HSIC
power domain to the GPC node.

Signed-off-by: Tyler Baker <tyler@opensourcefoundries.com>
---
 arch/arm/boot/dts/imx7s.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index 151ab34..9626a3e 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -602,6 +602,12 @@
 						reg = <IMX7_POWER_DOMAIN_PCIE_PHY>;
 						power-supply = <&reg_1p0d>;
 					};
+					pgc_usb_hsic_phy: pgc-usb-hsic-phy-domain {
+						#power-domain-cells = <0>;
+
+						reg = <IMX7_POWER_DOMAIN_USB_HSIC_PHY>;
+						power-supply = <&reg_1p2>;
+					};
 				};
 			};
 		};
-- 
2.9.3

^ permalink raw reply related

* [PATCH v1 5/6] ARM: dts: imx7d-sbc-iot: enable PCIe peripheral
From: tyler-yzvPICuk2AAEdKtRPRuaE5USO3DlRtUf @ 2017-12-05 22:27 UTC (permalink / raw)
  To: shawnguo-DgEjT+Ai2ygdnm+yROfE0A, festevam-Re5JQEeQqe8AvxtiuMwx3w,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, fabio.estevam-3arQi8VN3Tc,
	Tyler Baker
In-Reply-To: <20171205222707.11302-1-tyler-yzvPICuk2AAEdKtRPRuaE5USO3DlRtUf@public.gmane.org>

From: Tyler Baker <tyler-yzvPICuk2AAEdKtRPRuaE5USO3DlRtUf@public.gmane.org>

Add a PCIe device tree node to enable PCIe support.

Signed-off-by: Tyler Baker <tyler-yzvPICuk2AAEdKtRPRuaE5USO3DlRtUf@public.gmane.org>
---
 arch/arm/boot/dts/imx7d-sbc-iot-imx7.dts | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm/boot/dts/imx7d-sbc-iot-imx7.dts b/arch/arm/boot/dts/imx7d-sbc-iot-imx7.dts
index 67aa4b7..7f45fa2 100644
--- a/arch/arm/boot/dts/imx7d-sbc-iot-imx7.dts
+++ b/arch/arm/boot/dts/imx7d-sbc-iot-imx7.dts
@@ -79,6 +79,12 @@
 		>;
 	};
 
+	pinctrl_pcie: pciegrp {
+		fsl,pins = <
+			MX7D_PAD_EPDC_BDR1__GPIO2_IO29		0x34 /* PCIe RST */
+		>;
+	};
+
 	pinctrl_uart2: uart2grp {
 		fsl,pins = <
 			MX7D_PAD_LCD_ENABLE__UART2_DCE_TX	0x79 /* P7-12 */
@@ -119,6 +125,13 @@
 	};
 };
 
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcie>;
+	reset-gpio = <&gpio2 29 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
 &uart2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart2>;
-- 
2.9.3

--
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

* [PATCH v1 4/6] ARM: dts: imx7s: add node and supplies for vdd1p2
From: tyler @ 2017-12-05 22:27 UTC (permalink / raw)
  To: shawnguo, festevam, kernel
  Cc: robh+dt, mark.rutland, linux-arm-kernel, devicetree, linux-kernel,
	fabio.estevam, Tyler Baker
In-Reply-To: <20171205222707.11302-1-tyler@opensourcefoundries.com>

From: Tyler Baker <tyler@opensourcefoundries.com>

Add the regulator nodes and supplies for vdd1p2. This regulator is
used to power the GPC and USB HSIC PHY.

Signed-off-by: Tyler Baker <tyler@opensourcefoundries.com>
---
 arch/arm/boot/dts/imx7s.dtsi | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index 7b85659..151ab34 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -522,6 +522,20 @@
 					anatop-max-voltage = <1200000>;
 					anatop-enable-bit = <0>;
 				};
+
+				reg_1p2: regulator-vdd1p2@220 {
+					compatible = "fsl,anatop-regulator";
+					regulator-name = "vdd1p2";
+					regulator-min-microvolt = <1100000>;
+					regulator-max-microvolt = <1300000>;
+					anatop-reg-offset = <0x220>;
+					anatop-vol-bit-shift = <8>;
+					anatop-vol-bit-width = <5>;
+					anatop-min-bit-val = <8>;
+					anatop-min-voltage = <1100000>;
+					anatop-max-voltage = <1300000>;
+					anatop-enable-bit = <0>;
+				};
 			};
 
 			snvs: snvs@30370000 {
@@ -578,7 +592,7 @@
 				#interrupt-cells = <3>;
 				interrupt-parent = <&intc>;
 				#power-domain-cells = <1>;
-
+				vcc-supply = <&reg_1p2>;
 				pgc {
 					#address-cells = <1>;
 					#size-cells = <0>;
@@ -961,6 +975,7 @@
 				compatible = "usb-nop-xceiv";
 				clocks = <&clks IMX7D_USB_HSIC_ROOT_CLK>;
 				clock-names = "main_clk";
+				vcc-supply = <&reg_1p2>;
 			};
 
 			usdhc1: usdhc@30b40000 {
-- 
2.9.3

^ permalink raw reply related

* [PATCH v1 3/6] ARM: dts: imx7s: add dma support
From: tyler @ 2017-12-05 22:27 UTC (permalink / raw)
  To: shawnguo, festevam, kernel
  Cc: robh+dt, mark.rutland, linux-arm-kernel, devicetree, linux-kernel,
	fabio.estevam, Tyler Baker
In-Reply-To: <20171205222707.11302-1-tyler@opensourcefoundries.com>

From: Tyler Baker <tyler@opensourcefoundries.com>

Enable dma on all SPI interfaces.

Signed-off-by: Tyler Baker <tyler@opensourcefoundries.com>
---
 arch/arm/boot/dts/imx7s.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index 82ad26e..7b85659 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -700,6 +700,8 @@
 				clocks = <&clks IMX7D_ECSPI1_ROOT_CLK>,
 					<&clks IMX7D_ECSPI1_ROOT_CLK>;
 				clock-names = "ipg", "per";
+				dmas = <&sdma 0 7 1>, <&sdma 1 7 2>;
+				dma-names = "rx", "tx";
 				status = "disabled";
 			};
 
@@ -712,6 +714,8 @@
 				clocks = <&clks IMX7D_ECSPI2_ROOT_CLK>,
 					<&clks IMX7D_ECSPI2_ROOT_CLK>;
 				clock-names = "ipg", "per";
+				dmas = <&sdma 2 7 1>, <&sdma 3 7 2>;
+				dma-names = "rx", "tx";
 				status = "disabled";
 			};
 
@@ -724,6 +728,8 @@
 				clocks = <&clks IMX7D_ECSPI3_ROOT_CLK>,
 					<&clks IMX7D_ECSPI3_ROOT_CLK>;
 				clock-names = "ipg", "per";
+				dmas = <&sdma 4 7 1>, <&sdma 5 7 2>;
+				dma-names = "rx", "tx";
 				status = "disabled";
 			};
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH v1 2/6] ARM: dts: imx7d-cl-som: add nodes for usbh, and usbotg2
From: tyler-yzvPICuk2AAEdKtRPRuaE5USO3DlRtUf @ 2017-12-05 22:27 UTC (permalink / raw)
  To: shawnguo-DgEjT+Ai2ygdnm+yROfE0A, festevam-Re5JQEeQqe8AvxtiuMwx3w,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, fabio.estevam-3arQi8VN3Tc,
	Tyler Baker
In-Reply-To: <20171205222707.11302-1-tyler-yzvPICuk2AAEdKtRPRuaE5USO3DlRtUf@public.gmane.org>

From: Tyler Baker <tyler-yzvPICuk2AAEdKtRPRuaE5USO3DlRtUf@public.gmane.org>

Add device tree nodes for the USB hub, and USB OTG. i2c2 on this
platform supports low state retention power state so lets use it.

Signed-off-by: Tyler Baker <tyler-yzvPICuk2AAEdKtRPRuaE5USO3DlRtUf@public.gmane.org>
---
 arch/arm/boot/dts/imx7d-cl-som-imx7.dts | 34 ++++++++++++++++++++++++++-------
 1 file changed, 27 insertions(+), 7 deletions(-)

diff --git a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
index ae45af1..49bd371 100644
--- a/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
+++ b/arch/arm/boot/dts/imx7d-cl-som-imx7.dts
@@ -30,6 +30,16 @@
 		gpio = <&gpio1 5 GPIO_ACTIVE_HIGH>;
 		enable-active-high;
 	};
+
+	reg_usbh_nreset: regulator-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb_host_nreset";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&pca9555 6 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+	};
 };
 
 &cpu0 {
@@ -199,6 +209,16 @@
 	status = "okay";
 };
 
+&usbotg2 {
+	dr_mode = "host";
+	status = "okay";
+};
+
+&usbh {
+	vbus-supply = <&reg_usbh_nreset>;
+	status = "okay";
+};
+
 &usdhc3 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_usdhc3>;
@@ -247,13 +267,6 @@
 		>;
 	};
 
-	pinctrl_i2c2: i2c2grp {
-		fsl,pins = <
-			MX7D_PAD_I2C2_SDA__I2C2_SDA		0x4000007f
-			MX7D_PAD_I2C2_SCL__I2C2_SCL		0x4000007f
-		>;
-	};
-
 	pinctrl_uart1: uart1grp {
 		fsl,pins = <
 			MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX	0x79
@@ -284,4 +297,11 @@
 			MX7D_PAD_LPSR_GPIO1_IO05__GPIO1_IO5	0x14 /* OTG PWREN */
 		>;
 	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX7D_PAD_LPSR_GPIO1_IO07__I2C2_SDA		0x4000000f
+			MX7D_PAD_LPSR_GPIO1_IO06__I2C2_SCL		0x4000000f
+		>;
+	};
 };
-- 
2.9.3

--
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

* [PATCH v1 1/6] ARM: dts: imx7d-sbc-iot: add initial iot gateway dts
From: tyler @ 2017-12-05 22:27 UTC (permalink / raw)
  To: shawnguo, festevam, kernel
  Cc: robh+dt, mark.rutland, linux-arm-kernel, devicetree, linux-kernel,
	fabio.estevam, Tyler Baker, Ilya Ledvich
In-Reply-To: <20171205222707.11302-1-tyler@opensourcefoundries.com>

From: Tyler Baker <tyler@opensourcefoundries.com>

The Compulab IoT Gateway is based on an NXP i.MX7D, dual core
Cortex-A7 clocking at 1GHz. It supports up to 2GB of DDR3,
and 32GB of eMMC flash. Onboard, there are two gigabit
ethernet controllers, 4 x USB2, RS485, and CAN.

This platform is based on the imx7d-cl-som-imx7 module but
includes a baseboard with additional peripherals
which is what this device tree is meant to describe.

This work has been derrived from the Compulab Linux sources
based on v4.1.

Signed-off-by: Tyler Baker <tyler@opensourcefoundries.com>
Signed-off-by: Ilya Ledvich <ilya@compulab.co.il>
---
 arch/arm/boot/dts/Makefile               |   1 +
 arch/arm/boot/dts/imx7d-sbc-iot-imx7.dts | 156 +++++++++++++++++++++++++++++++
 2 files changed, 157 insertions(+)
 create mode 100644 arch/arm/boot/dts/imx7d-sbc-iot-imx7.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index d0381e9..0334137 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -515,6 +515,7 @@ dtb-$(CONFIG_SOC_IMX7D) += \
 	imx7d-nitrogen7.dtb \
 	imx7d-pico.dtb \
 	imx7d-sbc-imx7.dtb \
+	imx7d-sbc-iot-imx7.dtb \
 	imx7d-sdb.dtb \
 	imx7d-sdb-sht11.dtb \
 	imx7s-colibri-eval-v3.dtb \
diff --git a/arch/arm/boot/dts/imx7d-sbc-iot-imx7.dts b/arch/arm/boot/dts/imx7d-sbc-iot-imx7.dts
new file mode 100644
index 0000000..67aa4b7
--- /dev/null
+++ b/arch/arm/boot/dts/imx7d-sbc-iot-imx7.dts
@@ -0,0 +1,156 @@
+/*
+ * Support for CompuLab SBC-IOT-iMX7 Single Board Computer
+ *
+ * Copyright (C) 2017 CompuLab Ltd. - http://www.compulab.co.il/
+ * Author: Ilya Ledvich <ilya@compulab.co.il>
+ *
+ * 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.
+ */
+
+#include "imx7d-cl-som-imx7.dts"
+
+/ {
+	model = "CompuLab SBC-IOT-iMX7";
+	compatible = "compulab,sbc-iot-imx7", "compulab,cl-som-imx7", "fsl,imx7d";
+};
+
+&ecspi3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi3 &pinctrl_ecspi3_cs>;
+	cs-gpios = <&gpio4 11 0>;
+	status = "okay";
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+};
+
+&i2c4 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c4>;
+	status = "okay";
+
+	eeprom_iot@54 {
+		compatible = "atmel,24c08";
+		reg = <0x54>;
+		pagesize = <16>;
+	};
+};
+
+&iomuxc {
+	pinctrl_xpen: xpengrp {
+		fsl,pins = <
+			MX7D_PAD_LCD_DATA13__GPIO3_IO18		0x34 /* P7-4 - gpio82 */
+			MX7D_PAD_LCD_DATA12__GPIO3_IO17		0x34 /* P7-5 - gpio81 */
+		>;
+	};
+
+	pinctrl_ecspi3: ecspi3grp {
+		fsl,pins = <
+			MX7D_PAD_I2C1_SDA__ECSPI3_MOSI		0xf /* P7-8 */
+			MX7D_PAD_I2C1_SCL__ECSPI3_MISO		0xf /* P7-7 */
+			MX7D_PAD_I2C2_SCL__ECSPI3_SCLK		0xf /* P7-6 */
+		>;
+	};
+
+	pinctrl_ecspi3_cs: ecspi3_cs_grp {
+		fsl,pins = <
+			MX7D_PAD_I2C2_SDA__GPIO4_IO11		0x34 /* P7-9 */
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX7D_PAD_GPIO1_IO09__I2C3_SDA		0x4000000f /* P7-3 */
+			MX7D_PAD_GPIO1_IO08__I2C3_SCL		0x4000000f /* P7-2 */
+		>;
+	};
+
+	pinctrl_i2c4: i2c4grp {
+		fsl,pins = <
+			MX7D_PAD_GPIO1_IO11__I2C4_SDA		0x4000000f
+			MX7D_PAD_GPIO1_IO10__I2C4_SCL		0x4000000f
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX7D_PAD_LCD_ENABLE__UART2_DCE_TX	0x79 /* P7-12 */
+			MX7D_PAD_LCD_CLK__UART2_DCE_RX		0x79 /* P7-13 */
+			MX7D_PAD_LCD_VSYNC__UART2_DCE_CTS	0x79 /* P7-11 */
+			MX7D_PAD_LCD_HSYNC__UART2_DCE_RTS	0x79 /* P7-10 */
+		>;
+	};
+
+	pinctrl_uart5: uart5grp {
+		fsl,pins = <
+			MX7D_PAD_I2C4_SDA__UART5_DCE_TX		0x79 /* RS232-TX */
+			MX7D_PAD_I2C4_SCL__UART5_DCE_RX		0x79 /* RS232-RX */
+			MX7D_PAD_I2C3_SDA__UART5_DCE_RTS	0x79 /* RS232-RTS */
+			MX7D_PAD_I2C3_SCL__UART5_DCE_CTS	0x79 /* RS232-CTS */
+		>;
+	};
+
+	pinctrl_uart7: uart7grp {
+		fsl,pins = <
+			MX7D_PAD_ECSPI2_MOSI__UART7_DCE_TX	0x79 /* R485-TX */
+			MX7D_PAD_ECSPI2_SCLK__UART7_DCE_RX	0x79 /* R485-RX */
+			MX7D_PAD_ECSPI2_SS0__UART7_DCE_CTS	0x79 /* R485-CTS */
+			MX7D_PAD_ECSPI2_MISO__UART7_DCE_RTS	0x79 /* R485-TTS */
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX7D_PAD_SD1_CMD__SD1_CMD		0x59
+			MX7D_PAD_SD1_CLK__SD1_CLK		0x19
+			MX7D_PAD_SD1_DATA0__SD1_DATA0		0x59
+			MX7D_PAD_SD1_DATA1__SD1_DATA1		0x59
+			MX7D_PAD_SD1_DATA2__SD1_DATA2		0x59
+			MX7D_PAD_SD1_DATA3__SD1_DATA3		0x59
+			MX7D_PAD_SD1_CD_B__GPIO5_IO0		0x59 /* CD */
+		>;
+	};
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	assigned-clocks = <&clks IMX7D_UART2_ROOT_SRC>;
+	assigned-clock-parents = <&clks IMX7D_OSC_24M_CLK>;
+	uart-has-rtscts;
+	status = "okay";
+};
+
+&uart5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart5>;
+	assigned-clocks = <&clks IMX7D_UART5_ROOT_SRC>;
+	assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
+	uart-has-rtscts;
+	status = "okay";
+};
+
+&uart7 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart7>;
+	assigned-clocks = <&clks IMX7D_UART7_ROOT_SRC>;
+	assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
+	uart-has-rtscts;
+	status = "okay";
+};
+
+&usdhc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+	wp-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
+	enable-sdio-wakeup;
+	status = "okay";
+};
-- 
2.9.3

^ permalink raw reply related

* [PATCH v1 0/6] ARM: dts: introduce Compulab IoT Gateway
From: tyler-yzvPICuk2AAEdKtRPRuaE5USO3DlRtUf @ 2017-12-05 22:27 UTC (permalink / raw)
  To: shawnguo-DgEjT+Ai2ygdnm+yROfE0A, festevam-Re5JQEeQqe8AvxtiuMwx3w,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, fabio.estevam-3arQi8VN3Tc,
	Tyler Baker

From: Tyler Baker <tyler-yzvPICuk2AAEdKtRPRuaE5USO3DlRtUf@public.gmane.org>

The Compulab IoT Gateway is based on an NXP i.MX7D, dual core
Cortex-A7 clocking at 1GHz. It supports up to 2GB of DDR3,
and 32GB of eMMC flash. Onboard, there are two gigabit
ethernet controllers, 4 x USB2, RS485, and CAN.

It uses the same SoM as the cl-som-imx7, but includes a baseboard 
with additional I/O.

Compulab has provided patches for this platform based on v4.1. 
I've used these patches as reference to get things working on tip.

Changes for v1 (Requested by Fabio)
  * Squashed the dts build into the initial patch
  * Dropped the phy refclk patch from this series, submitting to PCI list
  * Removed fsl,spi-num-chipselects property
  * Removed LCD and DVI nodes, will follow up with a later series
  * s/fsl,uart-has-rtscts/uart-has-rtscts/g
  * Fixed regulator usage inside of simple-bus

The entire series is based on v4.15-rc2.

Tyler Baker (6):
  ARM: dts: imx7d-sbc-iot: add initial iot gateway dts
  ARM: dts: imx7d-cl-som: add nodes for usbh, and usbotg2
  ARM: dts: imx7s: add dma support
  ARM: dts: imx7s: add node and supplies for vdd1p2
  ARM: dts: imx7d-sbc-iot: enable PCIe peripheral
  ARM: dts: imx7s: add usb hsic phy domain

 arch/arm/boot/dts/Makefile               |   1 +
 arch/arm/boot/dts/imx7d-cl-som-imx7.dts  |  34 +++++--
 arch/arm/boot/dts/imx7d-sbc-iot-imx7.dts | 169 +++++++++++++++++++++++++++++++
 arch/arm/boot/dts/imx7s.dtsi             |  29 +++++-
 4 files changed, 225 insertions(+), 8 deletions(-)
 create mode 100644 arch/arm/boot/dts/imx7d-sbc-iot-imx7.dts

-- 
2.9.3

--
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] ARM: dts: sun8i: h3: enable USB OTG for NanoPi Neo board
From: Krzysztof Adamski @ 2017-12-05 22:10 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Rob Herring, Mark Rutland, Russell King, Chen-Yu Tsai, devicetree,
	linux-arm-kernel, linux-kernel
In-Reply-To: <20171205090706.et5a7dizkhn6auje@flea.lan>

On Tue, Dec 05, 2017 at 10:07:06AM +0100, Maxime Ripard wrote:
>> diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts
>> index 78f6c24952dd..14c3f137dbd3 100644
>> --- a/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts
>> +++ b/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts
>> @@ -53,3 +53,20 @@
>> 	allwinner,leds-active-low;
>> 	status = "okay";
>> };
>> +
>> +&usb_otg {
>> +	status = "okay";
>> +	dr_mode = "peripheral";
>> +};
>> +
>> +&usbphy {
>> +	usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
>> +};
>> +
>> +&ohci0 {
>> +	status = "okay";
>> +};
>> +
>> +&ehci0 {
>> +	status = "okay";
>> +};
>
>Please sort the nodes in alphabetical order.

Will do in v2 sent in separate e-mail.

>Also, does it make sense to add the OHCI and EHCI controller for a
>peripheral-only device?

It does. The reasoning is the same as for the OrangePi Zero board in the
patch by Icenowy Zheng (72897fa31fcf6222a11c6ebb0bcca25628bb1f7c) - the
host mode on this board should work if you have external power source.
In this case you can switch the mode via sysfs. I wanted to be
consistent with the approach taken for the OrangePi Zero board. I added
this reasoning to the commit message of v2.

Best regards,
Krzysztof Adamski

^ permalink raw reply

* Re: [PATCH V6 0/7] dmaengine: qcom_hidma: add support for bugfixed HW
From: Rafael J. Wysocki @ 2017-12-05 22:05 UTC (permalink / raw)
  To: Sinan Kaya, Sakari Ailus
  Cc: dmaengine, Timur Tabi, devicetree@vger.kernel.org,
	ACPI Devel Maling List, linux-arm-msm,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <1512493493-6464-1-git-send-email-okaya@codeaurora.org>

On Tue, Dec 5, 2017 at 6:04 PM, Sinan Kaya <okaya@codeaurora.org> wrote:
> Introduce new ACPI and OF device ids for thw HW along with the helper
> functions.
>
> Changes from v5:
> * use struct device as a calling parameter to get_match_data() callback
> so that we can reuse the existing OF API.
> * revert the change on acpi_get_match_data() to V4.
>
> Sinan Kaya (7):
>   Documentation: DT: qcom_hidma: Bump HW revision for the bugfixed HW
>   ACPI / bus: Introduce acpi_get_match_data() function
>   device property: Introduce a common API to fetch device match data
>   OF: properties: Implement get_match_data() callback
>   ACPI: properties: Implement get_match_data() callback
>   dmaengine: qcom_hidma: Add support for the new revision
>   dmaengine: qcom_hidma: Add identity register support

Sakari, can you please have a look at this series?

I'm particularly interested in your opinion on patches [2-3/7] and [5/7].

Thanks,
Rafael

^ 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