xref: /openbmc/linux/drivers/media/i2c/ov5647.c (revision cef66734)
13c2472a3SRamiro Oliveira /*
23c2472a3SRamiro Oliveira  * A V4L2 driver for OmniVision OV5647 cameras.
33c2472a3SRamiro Oliveira  *
43c2472a3SRamiro Oliveira  * Based on Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor driver
53c2472a3SRamiro Oliveira  * Copyright (C) 2011 Sylwester Nawrocki <s.nawrocki@samsung.com>
63c2472a3SRamiro Oliveira  *
73c2472a3SRamiro Oliveira  * Based on Omnivision OV7670 Camera Driver
83c2472a3SRamiro Oliveira  * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net>
93c2472a3SRamiro Oliveira  *
103c2472a3SRamiro Oliveira  * Copyright (C) 2016, Synopsys, Inc.
113c2472a3SRamiro Oliveira  *
123c2472a3SRamiro Oliveira  * This program is free software; you can redistribute it and/or
133c2472a3SRamiro Oliveira  * modify it under the terms of the GNU General Public License as
143c2472a3SRamiro Oliveira  * published by the Free Software Foundation version 2.
153c2472a3SRamiro Oliveira  *
163c2472a3SRamiro Oliveira  * This program is distributed .as is. WITHOUT ANY WARRANTY of any
173c2472a3SRamiro Oliveira  * kind, whether express or implied; without even the implied warranty
183c2472a3SRamiro Oliveira  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
193c2472a3SRamiro Oliveira  * GNU General Public License for more details.
203c2472a3SRamiro Oliveira  */
213c2472a3SRamiro Oliveira 
223c2472a3SRamiro Oliveira #include <linux/clk.h>
233c2472a3SRamiro Oliveira #include <linux/delay.h>
243c2472a3SRamiro Oliveira #include <linux/i2c.h>
253c2472a3SRamiro Oliveira #include <linux/init.h>
263c2472a3SRamiro Oliveira #include <linux/io.h>
273c2472a3SRamiro Oliveira #include <linux/module.h>
28859969b3SSakari Ailus #include <linux/of_graph.h>
293c2472a3SRamiro Oliveira #include <linux/slab.h>
303c2472a3SRamiro Oliveira #include <linux/videodev2.h>
313c2472a3SRamiro Oliveira #include <media/v4l2-device.h>
32859969b3SSakari Ailus #include <media/v4l2-fwnode.h>
333c2472a3SRamiro Oliveira #include <media/v4l2-image-sizes.h>
343c2472a3SRamiro Oliveira #include <media/v4l2-mediabus.h>
353c2472a3SRamiro Oliveira 
363c2472a3SRamiro Oliveira #define SENSOR_NAME "ov5647"
373c2472a3SRamiro Oliveira 
38cef66734SJacob Chen #define MIPI_CTRL00_CLOCK_LANE_GATE		BIT(5)
39cef66734SJacob Chen #define MIPI_CTRL00_BUS_IDLE			BIT(2)
40cef66734SJacob Chen #define MIPI_CTRL00_CLOCK_LANE_DISABLE		BIT(0)
41cef66734SJacob Chen 
42cef66734SJacob Chen #define OV5647_SW_STANDBY		0x0100
433c2472a3SRamiro Oliveira #define OV5647_SW_RESET			0x0103
443c2472a3SRamiro Oliveira #define OV5647_REG_CHIPID_H		0x300A
453c2472a3SRamiro Oliveira #define OV5647_REG_CHIPID_L		0x300B
46cef66734SJacob Chen #define OV5640_REG_PAD_OUT		0x300D
47cef66734SJacob Chen #define OV5647_REG_FRAME_OFF_NUMBER	0x4202
48cef66734SJacob Chen #define OV5647_REG_MIPI_CTRL00		0x4800
49cef66734SJacob Chen #define OV5647_REG_MIPI_CTRL14		0x4814
503c2472a3SRamiro Oliveira 
513c2472a3SRamiro Oliveira #define REG_TERM 0xfffe
523c2472a3SRamiro Oliveira #define VAL_TERM 0xfe
533c2472a3SRamiro Oliveira #define REG_DLY  0xffff
543c2472a3SRamiro Oliveira 
553c2472a3SRamiro Oliveira #define OV5647_ROW_START		0x01
563c2472a3SRamiro Oliveira #define OV5647_ROW_START_MIN		0
573c2472a3SRamiro Oliveira #define OV5647_ROW_START_MAX		2004
583c2472a3SRamiro Oliveira #define OV5647_ROW_START_DEF		54
593c2472a3SRamiro Oliveira 
603c2472a3SRamiro Oliveira #define OV5647_COLUMN_START		0x02
613c2472a3SRamiro Oliveira #define OV5647_COLUMN_START_MIN		0
623c2472a3SRamiro Oliveira #define OV5647_COLUMN_START_MAX		2750
633c2472a3SRamiro Oliveira #define OV5647_COLUMN_START_DEF		16
643c2472a3SRamiro Oliveira 
653c2472a3SRamiro Oliveira #define OV5647_WINDOW_HEIGHT		0x03
663c2472a3SRamiro Oliveira #define OV5647_WINDOW_HEIGHT_MIN	2
673c2472a3SRamiro Oliveira #define OV5647_WINDOW_HEIGHT_MAX	2006
683c2472a3SRamiro Oliveira #define OV5647_WINDOW_HEIGHT_DEF	1944
693c2472a3SRamiro Oliveira 
703c2472a3SRamiro Oliveira #define OV5647_WINDOW_WIDTH		0x04
713c2472a3SRamiro Oliveira #define OV5647_WINDOW_WIDTH_MIN		2
723c2472a3SRamiro Oliveira #define OV5647_WINDOW_WIDTH_MAX		2752
733c2472a3SRamiro Oliveira #define OV5647_WINDOW_WIDTH_DEF		2592
743c2472a3SRamiro Oliveira 
753c2472a3SRamiro Oliveira struct regval_list {
763c2472a3SRamiro Oliveira 	u16 addr;
773c2472a3SRamiro Oliveira 	u8 data;
783c2472a3SRamiro Oliveira };
793c2472a3SRamiro Oliveira 
803c2472a3SRamiro Oliveira struct ov5647 {
813c2472a3SRamiro Oliveira 	struct v4l2_subdev		sd;
823c2472a3SRamiro Oliveira 	struct media_pad		pad;
833c2472a3SRamiro Oliveira 	struct mutex			lock;
843c2472a3SRamiro Oliveira 	struct v4l2_mbus_framefmt	format;
853c2472a3SRamiro Oliveira 	unsigned int			width;
863c2472a3SRamiro Oliveira 	unsigned int			height;
873c2472a3SRamiro Oliveira 	int				power_count;
883c2472a3SRamiro Oliveira 	struct clk			*xclk;
893c2472a3SRamiro Oliveira };
903c2472a3SRamiro Oliveira 
913c2472a3SRamiro Oliveira static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
923c2472a3SRamiro Oliveira {
933c2472a3SRamiro Oliveira 	return container_of(sd, struct ov5647, sd);
943c2472a3SRamiro Oliveira }
953c2472a3SRamiro Oliveira 
963c2472a3SRamiro Oliveira static struct regval_list sensor_oe_disable_regs[] = {
973c2472a3SRamiro Oliveira 	{0x3000, 0x00},
983c2472a3SRamiro Oliveira 	{0x3001, 0x00},
993c2472a3SRamiro Oliveira 	{0x3002, 0x00},
1003c2472a3SRamiro Oliveira };
1013c2472a3SRamiro Oliveira 
1023c2472a3SRamiro Oliveira static struct regval_list sensor_oe_enable_regs[] = {
1033c2472a3SRamiro Oliveira 	{0x3000, 0x0f},
1043c2472a3SRamiro Oliveira 	{0x3001, 0xff},
1053c2472a3SRamiro Oliveira 	{0x3002, 0xe4},
1063c2472a3SRamiro Oliveira };
1073c2472a3SRamiro Oliveira 
1083c2472a3SRamiro Oliveira static struct regval_list ov5647_640x480[] = {
1093c2472a3SRamiro Oliveira 	{0x0100, 0x00},
1103c2472a3SRamiro Oliveira 	{0x0103, 0x01},
1113c2472a3SRamiro Oliveira 	{0x3034, 0x08},
1123c2472a3SRamiro Oliveira 	{0x3035, 0x21},
1133c2472a3SRamiro Oliveira 	{0x3036, 0x46},
1143c2472a3SRamiro Oliveira 	{0x303c, 0x11},
1153c2472a3SRamiro Oliveira 	{0x3106, 0xf5},
1163c2472a3SRamiro Oliveira 	{0x3821, 0x07},
1173c2472a3SRamiro Oliveira 	{0x3820, 0x41},
1183c2472a3SRamiro Oliveira 	{0x3827, 0xec},
1193c2472a3SRamiro Oliveira 	{0x370c, 0x0f},
1203c2472a3SRamiro Oliveira 	{0x3612, 0x59},
1213c2472a3SRamiro Oliveira 	{0x3618, 0x00},
1223c2472a3SRamiro Oliveira 	{0x5000, 0x06},
1233c2472a3SRamiro Oliveira 	{0x5001, 0x01},
1243c2472a3SRamiro Oliveira 	{0x5002, 0x41},
1253c2472a3SRamiro Oliveira 	{0x5003, 0x08},
1263c2472a3SRamiro Oliveira 	{0x5a00, 0x08},
1273c2472a3SRamiro Oliveira 	{0x3000, 0x00},
1283c2472a3SRamiro Oliveira 	{0x3001, 0x00},
1293c2472a3SRamiro Oliveira 	{0x3002, 0x00},
1303c2472a3SRamiro Oliveira 	{0x3016, 0x08},
1313c2472a3SRamiro Oliveira 	{0x3017, 0xe0},
1323c2472a3SRamiro Oliveira 	{0x3018, 0x44},
1333c2472a3SRamiro Oliveira 	{0x301c, 0xf8},
1343c2472a3SRamiro Oliveira 	{0x301d, 0xf0},
1353c2472a3SRamiro Oliveira 	{0x3a18, 0x00},
1363c2472a3SRamiro Oliveira 	{0x3a19, 0xf8},
1373c2472a3SRamiro Oliveira 	{0x3c01, 0x80},
1383c2472a3SRamiro Oliveira 	{0x3b07, 0x0c},
1393c2472a3SRamiro Oliveira 	{0x380c, 0x07},
1403c2472a3SRamiro Oliveira 	{0x380d, 0x68},
1413c2472a3SRamiro Oliveira 	{0x380e, 0x03},
1423c2472a3SRamiro Oliveira 	{0x380f, 0xd8},
1433c2472a3SRamiro Oliveira 	{0x3814, 0x31},
1443c2472a3SRamiro Oliveira 	{0x3815, 0x31},
1453c2472a3SRamiro Oliveira 	{0x3708, 0x64},
1463c2472a3SRamiro Oliveira 	{0x3709, 0x52},
1473c2472a3SRamiro Oliveira 	{0x3808, 0x02},
1483c2472a3SRamiro Oliveira 	{0x3809, 0x80},
1493c2472a3SRamiro Oliveira 	{0x380a, 0x01},
1503c2472a3SRamiro Oliveira 	{0x380b, 0xE0},
1513c2472a3SRamiro Oliveira 	{0x3801, 0x00},
1523c2472a3SRamiro Oliveira 	{0x3802, 0x00},
1533c2472a3SRamiro Oliveira 	{0x3803, 0x00},
1543c2472a3SRamiro Oliveira 	{0x3804, 0x0a},
1553c2472a3SRamiro Oliveira 	{0x3805, 0x3f},
1563c2472a3SRamiro Oliveira 	{0x3806, 0x07},
1573c2472a3SRamiro Oliveira 	{0x3807, 0xa1},
1583c2472a3SRamiro Oliveira 	{0x3811, 0x08},
1593c2472a3SRamiro Oliveira 	{0x3813, 0x02},
1603c2472a3SRamiro Oliveira 	{0x3630, 0x2e},
1613c2472a3SRamiro Oliveira 	{0x3632, 0xe2},
1623c2472a3SRamiro Oliveira 	{0x3633, 0x23},
1633c2472a3SRamiro Oliveira 	{0x3634, 0x44},
1643c2472a3SRamiro Oliveira 	{0x3636, 0x06},
1653c2472a3SRamiro Oliveira 	{0x3620, 0x64},
1663c2472a3SRamiro Oliveira 	{0x3621, 0xe0},
1673c2472a3SRamiro Oliveira 	{0x3600, 0x37},
1683c2472a3SRamiro Oliveira 	{0x3704, 0xa0},
1693c2472a3SRamiro Oliveira 	{0x3703, 0x5a},
1703c2472a3SRamiro Oliveira 	{0x3715, 0x78},
1713c2472a3SRamiro Oliveira 	{0x3717, 0x01},
1723c2472a3SRamiro Oliveira 	{0x3731, 0x02},
1733c2472a3SRamiro Oliveira 	{0x370b, 0x60},
1743c2472a3SRamiro Oliveira 	{0x3705, 0x1a},
1753c2472a3SRamiro Oliveira 	{0x3f05, 0x02},
1763c2472a3SRamiro Oliveira 	{0x3f06, 0x10},
1773c2472a3SRamiro Oliveira 	{0x3f01, 0x0a},
1783c2472a3SRamiro Oliveira 	{0x3a08, 0x01},
1793c2472a3SRamiro Oliveira 	{0x3a09, 0x27},
1803c2472a3SRamiro Oliveira 	{0x3a0a, 0x00},
1813c2472a3SRamiro Oliveira 	{0x3a0b, 0xf6},
1823c2472a3SRamiro Oliveira 	{0x3a0d, 0x04},
1833c2472a3SRamiro Oliveira 	{0x3a0e, 0x03},
1843c2472a3SRamiro Oliveira 	{0x3a0f, 0x58},
1853c2472a3SRamiro Oliveira 	{0x3a10, 0x50},
1863c2472a3SRamiro Oliveira 	{0x3a1b, 0x58},
1873c2472a3SRamiro Oliveira 	{0x3a1e, 0x50},
1883c2472a3SRamiro Oliveira 	{0x3a11, 0x60},
1893c2472a3SRamiro Oliveira 	{0x3a1f, 0x28},
1903c2472a3SRamiro Oliveira 	{0x4001, 0x02},
1913c2472a3SRamiro Oliveira 	{0x4004, 0x02},
1923c2472a3SRamiro Oliveira 	{0x4000, 0x09},
1933c2472a3SRamiro Oliveira 	{0x4837, 0x24},
1943c2472a3SRamiro Oliveira 	{0x4050, 0x6e},
1953c2472a3SRamiro Oliveira 	{0x4051, 0x8f},
1963c2472a3SRamiro Oliveira 	{0x0100, 0x01},
1973c2472a3SRamiro Oliveira };
1983c2472a3SRamiro Oliveira 
1993c2472a3SRamiro Oliveira static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
2003c2472a3SRamiro Oliveira {
2013c2472a3SRamiro Oliveira 	int ret;
2023c2472a3SRamiro Oliveira 	unsigned char data[3] = { reg >> 8, reg & 0xff, val};
2033c2472a3SRamiro Oliveira 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2043c2472a3SRamiro Oliveira 
2053c2472a3SRamiro Oliveira 	ret = i2c_master_send(client, data, 3);
2063c2472a3SRamiro Oliveira 	if (ret < 0)
2073c2472a3SRamiro Oliveira 		dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
2083c2472a3SRamiro Oliveira 				__func__, reg);
2093c2472a3SRamiro Oliveira 
2103c2472a3SRamiro Oliveira 	return ret;
2113c2472a3SRamiro Oliveira }
2123c2472a3SRamiro Oliveira 
2133c2472a3SRamiro Oliveira static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val)
2143c2472a3SRamiro Oliveira {
2153c2472a3SRamiro Oliveira 	int ret;
2163c2472a3SRamiro Oliveira 	unsigned char data_w[2] = { reg >> 8, reg & 0xff };
2173c2472a3SRamiro Oliveira 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2183c2472a3SRamiro Oliveira 
2193c2472a3SRamiro Oliveira 	ret = i2c_master_send(client, data_w, 2);
2203c2472a3SRamiro Oliveira 	if (ret < 0) {
2213c2472a3SRamiro Oliveira 		dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
2223c2472a3SRamiro Oliveira 			__func__, reg);
2233c2472a3SRamiro Oliveira 		return ret;
2243c2472a3SRamiro Oliveira 	}
2253c2472a3SRamiro Oliveira 
2263c2472a3SRamiro Oliveira 	ret = i2c_master_recv(client, val, 1);
2273c2472a3SRamiro Oliveira 	if (ret < 0)
2283c2472a3SRamiro Oliveira 		dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n",
2293c2472a3SRamiro Oliveira 				__func__, reg);
2303c2472a3SRamiro Oliveira 
2313c2472a3SRamiro Oliveira 	return ret;
2323c2472a3SRamiro Oliveira }
2333c2472a3SRamiro Oliveira 
2343c2472a3SRamiro Oliveira static int ov5647_write_array(struct v4l2_subdev *sd,
2353c2472a3SRamiro Oliveira 				struct regval_list *regs, int array_size)
2363c2472a3SRamiro Oliveira {
2373c2472a3SRamiro Oliveira 	int i, ret;
2383c2472a3SRamiro Oliveira 
2393c2472a3SRamiro Oliveira 	for (i = 0; i < array_size; i++) {
2403c2472a3SRamiro Oliveira 		ret = ov5647_write(sd, regs[i].addr, regs[i].data);
2413c2472a3SRamiro Oliveira 		if (ret < 0)
2423c2472a3SRamiro Oliveira 			return ret;
2433c2472a3SRamiro Oliveira 	}
2443c2472a3SRamiro Oliveira 
2453c2472a3SRamiro Oliveira 	return 0;
2463c2472a3SRamiro Oliveira }
2473c2472a3SRamiro Oliveira 
2483c2472a3SRamiro Oliveira static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
2493c2472a3SRamiro Oliveira {
2503c2472a3SRamiro Oliveira 	u8 channel_id;
2513c2472a3SRamiro Oliveira 	int ret;
2523c2472a3SRamiro Oliveira 
253cef66734SJacob Chen 	ret = ov5647_read(sd, OV5647_REG_MIPI_CTRL14, &channel_id);
2543c2472a3SRamiro Oliveira 	if (ret < 0)
2553c2472a3SRamiro Oliveira 		return ret;
2563c2472a3SRamiro Oliveira 
2573c2472a3SRamiro Oliveira 	channel_id &= ~(3 << 6);
258cef66734SJacob Chen 	return ov5647_write(sd, OV5647_REG_MIPI_CTRL14, channel_id | (channel << 6));
2593c2472a3SRamiro Oliveira }
2603c2472a3SRamiro Oliveira 
2613c2472a3SRamiro Oliveira static int ov5647_stream_on(struct v4l2_subdev *sd)
2623c2472a3SRamiro Oliveira {
2633c2472a3SRamiro Oliveira 	int ret;
2643c2472a3SRamiro Oliveira 
265cef66734SJacob Chen 	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_BUS_IDLE);
2667bc9f038SJacob Chen 	if (ret < 0)
2677bc9f038SJacob Chen 		return ret;
2687bc9f038SJacob Chen 
269cef66734SJacob Chen 	ret = ov5647_write(sd, OV5647_REG_FRAME_OFF_NUMBER, 0x00);
2703c2472a3SRamiro Oliveira 	if (ret < 0)
2713c2472a3SRamiro Oliveira 		return ret;
2723c2472a3SRamiro Oliveira 
273cef66734SJacob Chen 	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x00);
2743c2472a3SRamiro Oliveira }
2753c2472a3SRamiro Oliveira 
2763c2472a3SRamiro Oliveira static int ov5647_stream_off(struct v4l2_subdev *sd)
2773c2472a3SRamiro Oliveira {
2783c2472a3SRamiro Oliveira 	int ret;
2793c2472a3SRamiro Oliveira 
280cef66734SJacob Chen 	ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE
281cef66734SJacob Chen 			   | MIPI_CTRL00_BUS_IDLE | MIPI_CTRL00_CLOCK_LANE_DISABLE);
2827bc9f038SJacob Chen 	if (ret < 0)
2837bc9f038SJacob Chen 		return ret;
2847bc9f038SJacob Chen 
285cef66734SJacob Chen 	ret = ov5647_write(sd, OV5647_REG_FRAME_OFF_NUMBER, 0x0f);
2863c2472a3SRamiro Oliveira 	if (ret < 0)
2873c2472a3SRamiro Oliveira 		return ret;
2883c2472a3SRamiro Oliveira 
289cef66734SJacob Chen 	return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
2903c2472a3SRamiro Oliveira }
2913c2472a3SRamiro Oliveira 
2923c2472a3SRamiro Oliveira static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
2933c2472a3SRamiro Oliveira {
2943c2472a3SRamiro Oliveira 	int ret;
2953c2472a3SRamiro Oliveira 	u8 rdval;
2963c2472a3SRamiro Oliveira 
297cef66734SJacob Chen 	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
2983c2472a3SRamiro Oliveira 	if (ret < 0)
2993c2472a3SRamiro Oliveira 		return ret;
3003c2472a3SRamiro Oliveira 
3013c2472a3SRamiro Oliveira 	if (standby)
3023c2472a3SRamiro Oliveira 		rdval &= ~0x01;
3033c2472a3SRamiro Oliveira 	else
3043c2472a3SRamiro Oliveira 		rdval |= 0x01;
3053c2472a3SRamiro Oliveira 
306cef66734SJacob Chen 	return ov5647_write(sd, OV5647_SW_STANDBY, rdval);
3073c2472a3SRamiro Oliveira }
3083c2472a3SRamiro Oliveira 
3093c2472a3SRamiro Oliveira static int __sensor_init(struct v4l2_subdev *sd)
3103c2472a3SRamiro Oliveira {
3113c2472a3SRamiro Oliveira 	int ret;
3123c2472a3SRamiro Oliveira 	u8 resetval, rdval;
3133c2472a3SRamiro Oliveira 	struct i2c_client *client = v4l2_get_subdevdata(sd);
3143c2472a3SRamiro Oliveira 
315cef66734SJacob Chen 	ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
3163c2472a3SRamiro Oliveira 	if (ret < 0)
3173c2472a3SRamiro Oliveira 		return ret;
3183c2472a3SRamiro Oliveira 
3193c2472a3SRamiro Oliveira 	ret = ov5647_write_array(sd, ov5647_640x480,
3203c2472a3SRamiro Oliveira 					ARRAY_SIZE(ov5647_640x480));
3213c2472a3SRamiro Oliveira 	if (ret < 0) {
3223c2472a3SRamiro Oliveira 		dev_err(&client->dev, "write sensor default regs error\n");
3233c2472a3SRamiro Oliveira 		return ret;
3243c2472a3SRamiro Oliveira 	}
3253c2472a3SRamiro Oliveira 
3263c2472a3SRamiro Oliveira 	ret = ov5647_set_virtual_channel(sd, 0);
3273c2472a3SRamiro Oliveira 	if (ret < 0)
3283c2472a3SRamiro Oliveira 		return ret;
3293c2472a3SRamiro Oliveira 
330cef66734SJacob Chen 	ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval);
3313c2472a3SRamiro Oliveira 	if (ret < 0)
3323c2472a3SRamiro Oliveira 		return ret;
3333c2472a3SRamiro Oliveira 
3343c2472a3SRamiro Oliveira 	if (!(resetval & 0x01)) {
3353c2472a3SRamiro Oliveira 		dev_err(&client->dev, "Device was in SW standby");
336cef66734SJacob Chen 		ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01);
3373c2472a3SRamiro Oliveira 		if (ret < 0)
3383c2472a3SRamiro Oliveira 			return ret;
3393c2472a3SRamiro Oliveira 	}
3403c2472a3SRamiro Oliveira 
3417bc9f038SJacob Chen 	/*
3427bc9f038SJacob Chen 	 * stream off to make the clock lane into LP-11 state.
3437bc9f038SJacob Chen 	 */
3447bc9f038SJacob Chen 	return ov5647_stream_off(sd);
3453c2472a3SRamiro Oliveira }
3463c2472a3SRamiro Oliveira 
3473c2472a3SRamiro Oliveira static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
3483c2472a3SRamiro Oliveira {
3493c2472a3SRamiro Oliveira 	int ret = 0;
3503c2472a3SRamiro Oliveira 	struct ov5647 *ov5647 = to_state(sd);
3513c2472a3SRamiro Oliveira 	struct i2c_client *client = v4l2_get_subdevdata(sd);
3523c2472a3SRamiro Oliveira 
3533c2472a3SRamiro Oliveira 	mutex_lock(&ov5647->lock);
3543c2472a3SRamiro Oliveira 
3553c2472a3SRamiro Oliveira 	if (on && !ov5647->power_count)	{
3563c2472a3SRamiro Oliveira 		dev_dbg(&client->dev, "OV5647 power on\n");
3573c2472a3SRamiro Oliveira 
3583c2472a3SRamiro Oliveira 		ret = clk_prepare_enable(ov5647->xclk);
3593c2472a3SRamiro Oliveira 		if (ret < 0) {
3603c2472a3SRamiro Oliveira 			dev_err(&client->dev, "clk prepare enable failed\n");
3613c2472a3SRamiro Oliveira 			goto out;
3623c2472a3SRamiro Oliveira 		}
3633c2472a3SRamiro Oliveira 
3643c2472a3SRamiro Oliveira 		ret = ov5647_write_array(sd, sensor_oe_enable_regs,
3653c2472a3SRamiro Oliveira 				ARRAY_SIZE(sensor_oe_enable_regs));
3663c2472a3SRamiro Oliveira 		if (ret < 0) {
3673c2472a3SRamiro Oliveira 			clk_disable_unprepare(ov5647->xclk);
3683c2472a3SRamiro Oliveira 			dev_err(&client->dev,
3693c2472a3SRamiro Oliveira 				"write sensor_oe_enable_regs error\n");
3703c2472a3SRamiro Oliveira 			goto out;
3713c2472a3SRamiro Oliveira 		}
3723c2472a3SRamiro Oliveira 
3733c2472a3SRamiro Oliveira 		ret = __sensor_init(sd);
3743c2472a3SRamiro Oliveira 		if (ret < 0) {
3753c2472a3SRamiro Oliveira 			clk_disable_unprepare(ov5647->xclk);
3763c2472a3SRamiro Oliveira 			dev_err(&client->dev,
3773c2472a3SRamiro Oliveira 				"Camera not available, check Power\n");
3783c2472a3SRamiro Oliveira 			goto out;
3793c2472a3SRamiro Oliveira 		}
3803c2472a3SRamiro Oliveira 	} else if (!on && ov5647->power_count == 1) {
3813c2472a3SRamiro Oliveira 		dev_dbg(&client->dev, "OV5647 power off\n");
3823c2472a3SRamiro Oliveira 
3833c2472a3SRamiro Oliveira 		ret = ov5647_write_array(sd, sensor_oe_disable_regs,
3843c2472a3SRamiro Oliveira 				ARRAY_SIZE(sensor_oe_disable_regs));
3853c2472a3SRamiro Oliveira 
3863c2472a3SRamiro Oliveira 		if (ret < 0)
3873c2472a3SRamiro Oliveira 			dev_dbg(&client->dev, "disable oe failed\n");
3883c2472a3SRamiro Oliveira 
3893c2472a3SRamiro Oliveira 		ret = set_sw_standby(sd, true);
3903c2472a3SRamiro Oliveira 
3913c2472a3SRamiro Oliveira 		if (ret < 0)
3923c2472a3SRamiro Oliveira 			dev_dbg(&client->dev, "soft stby failed\n");
3933c2472a3SRamiro Oliveira 
3943c2472a3SRamiro Oliveira 		clk_disable_unprepare(ov5647->xclk);
3953c2472a3SRamiro Oliveira 	}
3963c2472a3SRamiro Oliveira 
3973c2472a3SRamiro Oliveira 	/* Update the power count. */
3983c2472a3SRamiro Oliveira 	ov5647->power_count += on ? 1 : -1;
3993c2472a3SRamiro Oliveira 	WARN_ON(ov5647->power_count < 0);
4003c2472a3SRamiro Oliveira 
4013c2472a3SRamiro Oliveira out:
4023c2472a3SRamiro Oliveira 	mutex_unlock(&ov5647->lock);
4033c2472a3SRamiro Oliveira 
4043c2472a3SRamiro Oliveira 	return ret;
4053c2472a3SRamiro Oliveira }
4063c2472a3SRamiro Oliveira 
4073c2472a3SRamiro Oliveira #ifdef CONFIG_VIDEO_ADV_DEBUG
4083c2472a3SRamiro Oliveira static int ov5647_sensor_get_register(struct v4l2_subdev *sd,
4093c2472a3SRamiro Oliveira 				struct v4l2_dbg_register *reg)
4103c2472a3SRamiro Oliveira {
4113c2472a3SRamiro Oliveira 	u8 val;
4123c2472a3SRamiro Oliveira 	int ret;
4133c2472a3SRamiro Oliveira 
4143c2472a3SRamiro Oliveira 	ret = ov5647_read(sd, reg->reg & 0xff, &val);
4153c2472a3SRamiro Oliveira 	if (ret < 0)
4163c2472a3SRamiro Oliveira 		return ret;
4173c2472a3SRamiro Oliveira 
4183c2472a3SRamiro Oliveira 	reg->val = val;
4193c2472a3SRamiro Oliveira 	reg->size = 1;
4203c2472a3SRamiro Oliveira 
4213c2472a3SRamiro Oliveira 	return 0;
4223c2472a3SRamiro Oliveira }
4233c2472a3SRamiro Oliveira 
4243c2472a3SRamiro Oliveira static int ov5647_sensor_set_register(struct v4l2_subdev *sd,
4253c2472a3SRamiro Oliveira 				const struct v4l2_dbg_register *reg)
4263c2472a3SRamiro Oliveira {
4273c2472a3SRamiro Oliveira 	return ov5647_write(sd, reg->reg & 0xff, reg->val & 0xff);
4283c2472a3SRamiro Oliveira }
4293c2472a3SRamiro Oliveira #endif
4303c2472a3SRamiro Oliveira 
4313c2472a3SRamiro Oliveira /**
4323c2472a3SRamiro Oliveira  * @short Subdev core operations registration
4333c2472a3SRamiro Oliveira  */
4343c2472a3SRamiro Oliveira static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
4353c2472a3SRamiro Oliveira 	.s_power		= ov5647_sensor_power,
4363c2472a3SRamiro Oliveira #ifdef CONFIG_VIDEO_ADV_DEBUG
4373c2472a3SRamiro Oliveira 	.g_register		= ov5647_sensor_get_register,
4383c2472a3SRamiro Oliveira 	.s_register		= ov5647_sensor_set_register,
4393c2472a3SRamiro Oliveira #endif
4403c2472a3SRamiro Oliveira };
4413c2472a3SRamiro Oliveira 
4423c2472a3SRamiro Oliveira static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
4433c2472a3SRamiro Oliveira {
4443c2472a3SRamiro Oliveira 	if (enable)
4453c2472a3SRamiro Oliveira 		return ov5647_stream_on(sd);
4463c2472a3SRamiro Oliveira 	else
4473c2472a3SRamiro Oliveira 		return ov5647_stream_off(sd);
4483c2472a3SRamiro Oliveira }
4493c2472a3SRamiro Oliveira 
4503c2472a3SRamiro Oliveira static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
4513c2472a3SRamiro Oliveira 	.s_stream =		ov5647_s_stream,
4523c2472a3SRamiro Oliveira };
4533c2472a3SRamiro Oliveira 
4543c2472a3SRamiro Oliveira static int ov5647_enum_mbus_code(struct v4l2_subdev *sd,
4553c2472a3SRamiro Oliveira 				struct v4l2_subdev_pad_config *cfg,
4563c2472a3SRamiro Oliveira 				struct v4l2_subdev_mbus_code_enum *code)
4573c2472a3SRamiro Oliveira {
4583c2472a3SRamiro Oliveira 	if (code->index > 0)
4593c2472a3SRamiro Oliveira 		return -EINVAL;
4603c2472a3SRamiro Oliveira 
4613c2472a3SRamiro Oliveira 	code->code = MEDIA_BUS_FMT_SBGGR8_1X8;
4623c2472a3SRamiro Oliveira 
4633c2472a3SRamiro Oliveira 	return 0;
4643c2472a3SRamiro Oliveira }
4653c2472a3SRamiro Oliveira 
4663c2472a3SRamiro Oliveira static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
4673c2472a3SRamiro Oliveira 	.enum_mbus_code = ov5647_enum_mbus_code,
4683c2472a3SRamiro Oliveira };
4693c2472a3SRamiro Oliveira 
4703c2472a3SRamiro Oliveira static const struct v4l2_subdev_ops ov5647_subdev_ops = {
4713c2472a3SRamiro Oliveira 	.core		= &ov5647_subdev_core_ops,
4723c2472a3SRamiro Oliveira 	.video		= &ov5647_subdev_video_ops,
4733c2472a3SRamiro Oliveira 	.pad		= &ov5647_subdev_pad_ops,
4743c2472a3SRamiro Oliveira };
4753c2472a3SRamiro Oliveira 
4763c2472a3SRamiro Oliveira static int ov5647_detect(struct v4l2_subdev *sd)
4773c2472a3SRamiro Oliveira {
4783c2472a3SRamiro Oliveira 	u8 read;
4793c2472a3SRamiro Oliveira 	int ret;
4803c2472a3SRamiro Oliveira 	struct i2c_client *client = v4l2_get_subdevdata(sd);
4813c2472a3SRamiro Oliveira 
4823c2472a3SRamiro Oliveira 	ret = ov5647_write(sd, OV5647_SW_RESET, 0x01);
4833c2472a3SRamiro Oliveira 	if (ret < 0)
4843c2472a3SRamiro Oliveira 		return ret;
4853c2472a3SRamiro Oliveira 
4863c2472a3SRamiro Oliveira 	ret = ov5647_read(sd, OV5647_REG_CHIPID_H, &read);
4873c2472a3SRamiro Oliveira 	if (ret < 0)
4883c2472a3SRamiro Oliveira 		return ret;
4893c2472a3SRamiro Oliveira 
4903c2472a3SRamiro Oliveira 	if (read != 0x56) {
4913c2472a3SRamiro Oliveira 		dev_err(&client->dev, "ID High expected 0x56 got %x", read);
4923c2472a3SRamiro Oliveira 		return -ENODEV;
4933c2472a3SRamiro Oliveira 	}
4943c2472a3SRamiro Oliveira 
4953c2472a3SRamiro Oliveira 	ret = ov5647_read(sd, OV5647_REG_CHIPID_L, &read);
4963c2472a3SRamiro Oliveira 	if (ret < 0)
4973c2472a3SRamiro Oliveira 		return ret;
4983c2472a3SRamiro Oliveira 
4993c2472a3SRamiro Oliveira 	if (read != 0x47) {
5003c2472a3SRamiro Oliveira 		dev_err(&client->dev, "ID Low expected 0x47 got %x", read);
5013c2472a3SRamiro Oliveira 		return -ENODEV;
5023c2472a3SRamiro Oliveira 	}
5033c2472a3SRamiro Oliveira 
5043c2472a3SRamiro Oliveira 	return ov5647_write(sd, OV5647_SW_RESET, 0x00);
5053c2472a3SRamiro Oliveira }
5063c2472a3SRamiro Oliveira 
5073c2472a3SRamiro Oliveira static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
5083c2472a3SRamiro Oliveira {
5093c2472a3SRamiro Oliveira 	struct v4l2_mbus_framefmt *format =
5103c2472a3SRamiro Oliveira 				v4l2_subdev_get_try_format(sd, fh->pad, 0);
5113c2472a3SRamiro Oliveira 	struct v4l2_rect *crop =
5123c2472a3SRamiro Oliveira 				v4l2_subdev_get_try_crop(sd, fh->pad, 0);
5133c2472a3SRamiro Oliveira 
5143c2472a3SRamiro Oliveira 	crop->left = OV5647_COLUMN_START_DEF;
5153c2472a3SRamiro Oliveira 	crop->top = OV5647_ROW_START_DEF;
5163c2472a3SRamiro Oliveira 	crop->width = OV5647_WINDOW_WIDTH_DEF;
5173c2472a3SRamiro Oliveira 	crop->height = OV5647_WINDOW_HEIGHT_DEF;
5183c2472a3SRamiro Oliveira 
5193c2472a3SRamiro Oliveira 	format->code = MEDIA_BUS_FMT_SBGGR8_1X8;
5203c2472a3SRamiro Oliveira 
5213c2472a3SRamiro Oliveira 	format->width = OV5647_WINDOW_WIDTH_DEF;
5223c2472a3SRamiro Oliveira 	format->height = OV5647_WINDOW_HEIGHT_DEF;
5233c2472a3SRamiro Oliveira 	format->field = V4L2_FIELD_NONE;
5243c2472a3SRamiro Oliveira 	format->colorspace = V4L2_COLORSPACE_SRGB;
5253c2472a3SRamiro Oliveira 
5263c2472a3SRamiro Oliveira 	return 0;
5273c2472a3SRamiro Oliveira }
5283c2472a3SRamiro Oliveira 
5293c2472a3SRamiro Oliveira static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = {
5303c2472a3SRamiro Oliveira 	.open = ov5647_open,
5313c2472a3SRamiro Oliveira };
5323c2472a3SRamiro Oliveira 
5333c2472a3SRamiro Oliveira static int ov5647_parse_dt(struct device_node *np)
5343c2472a3SRamiro Oliveira {
535859969b3SSakari Ailus 	struct v4l2_fwnode_endpoint bus_cfg;
5363c2472a3SRamiro Oliveira 	struct device_node *ep;
5373c2472a3SRamiro Oliveira 
5383c2472a3SRamiro Oliveira 	int ret;
5393c2472a3SRamiro Oliveira 
5403c2472a3SRamiro Oliveira 	ep = of_graph_get_next_endpoint(np, NULL);
5413c2472a3SRamiro Oliveira 	if (!ep)
5423c2472a3SRamiro Oliveira 		return -EINVAL;
5433c2472a3SRamiro Oliveira 
544859969b3SSakari Ailus 	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
5453c2472a3SRamiro Oliveira 
5463c2472a3SRamiro Oliveira 	of_node_put(ep);
5473c2472a3SRamiro Oliveira 	return ret;
5483c2472a3SRamiro Oliveira }
5493c2472a3SRamiro Oliveira 
5503c2472a3SRamiro Oliveira static int ov5647_probe(struct i2c_client *client,
5513c2472a3SRamiro Oliveira 			const struct i2c_device_id *id)
5523c2472a3SRamiro Oliveira {
5533c2472a3SRamiro Oliveira 	struct device *dev = &client->dev;
5543c2472a3SRamiro Oliveira 	struct ov5647 *sensor;
5553c2472a3SRamiro Oliveira 	int ret;
5563c2472a3SRamiro Oliveira 	struct v4l2_subdev *sd;
5573c2472a3SRamiro Oliveira 	struct device_node *np = client->dev.of_node;
5583c2472a3SRamiro Oliveira 	u32 xclk_freq;
5593c2472a3SRamiro Oliveira 
5603c2472a3SRamiro Oliveira 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
5613c2472a3SRamiro Oliveira 	if (!sensor)
5623c2472a3SRamiro Oliveira 		return -ENOMEM;
5633c2472a3SRamiro Oliveira 
5643c2472a3SRamiro Oliveira 	if (IS_ENABLED(CONFIG_OF) && np) {
5653c2472a3SRamiro Oliveira 		ret = ov5647_parse_dt(np);
5663c2472a3SRamiro Oliveira 		if (ret) {
5673c2472a3SRamiro Oliveira 			dev_err(dev, "DT parsing error: %d\n", ret);
5683c2472a3SRamiro Oliveira 			return ret;
5693c2472a3SRamiro Oliveira 		}
5703c2472a3SRamiro Oliveira 	}
5713c2472a3SRamiro Oliveira 
5723c2472a3SRamiro Oliveira 	/* get system clock (xclk) */
5733c2472a3SRamiro Oliveira 	sensor->xclk = devm_clk_get(dev, NULL);
5743c2472a3SRamiro Oliveira 	if (IS_ERR(sensor->xclk)) {
5753c2472a3SRamiro Oliveira 		dev_err(dev, "could not get xclk");
5763c2472a3SRamiro Oliveira 		return PTR_ERR(sensor->xclk);
5773c2472a3SRamiro Oliveira 	}
5783c2472a3SRamiro Oliveira 
5793c2472a3SRamiro Oliveira 	xclk_freq = clk_get_rate(sensor->xclk);
5803c2472a3SRamiro Oliveira 	if (xclk_freq != 25000000) {
5813c2472a3SRamiro Oliveira 		dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq);
5823c2472a3SRamiro Oliveira 		return -EINVAL;
5833c2472a3SRamiro Oliveira 	}
5843c2472a3SRamiro Oliveira 
5853c2472a3SRamiro Oliveira 	mutex_init(&sensor->lock);
5863c2472a3SRamiro Oliveira 
5873c2472a3SRamiro Oliveira 	sd = &sensor->sd;
5883c2472a3SRamiro Oliveira 	v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops);
5893c2472a3SRamiro Oliveira 	sensor->sd.internal_ops = &ov5647_subdev_internal_ops;
5903c2472a3SRamiro Oliveira 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
5913c2472a3SRamiro Oliveira 
5923c2472a3SRamiro Oliveira 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
5933c2472a3SRamiro Oliveira 	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
5943c2472a3SRamiro Oliveira 	ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad);
5953c2472a3SRamiro Oliveira 	if (ret < 0)
5963c2472a3SRamiro Oliveira 		goto mutex_remove;
5973c2472a3SRamiro Oliveira 
5983c2472a3SRamiro Oliveira 	ret = ov5647_detect(sd);
5993c2472a3SRamiro Oliveira 	if (ret < 0)
6003c2472a3SRamiro Oliveira 		goto error;
6013c2472a3SRamiro Oliveira 
6023c2472a3SRamiro Oliveira 	ret = v4l2_async_register_subdev(sd);
6033c2472a3SRamiro Oliveira 	if (ret < 0)
6043c2472a3SRamiro Oliveira 		goto error;
6053c2472a3SRamiro Oliveira 
6063c2472a3SRamiro Oliveira 	dev_dbg(dev, "OmniVision OV5647 camera driver probed\n");
6073c2472a3SRamiro Oliveira 	return 0;
6083c2472a3SRamiro Oliveira error:
6093c2472a3SRamiro Oliveira 	media_entity_cleanup(&sd->entity);
6103c2472a3SRamiro Oliveira mutex_remove:
6113c2472a3SRamiro Oliveira 	mutex_destroy(&sensor->lock);
6123c2472a3SRamiro Oliveira 	return ret;
6133c2472a3SRamiro Oliveira }
6143c2472a3SRamiro Oliveira 
6153c2472a3SRamiro Oliveira static int ov5647_remove(struct i2c_client *client)
6163c2472a3SRamiro Oliveira {
6173c2472a3SRamiro Oliveira 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
6183c2472a3SRamiro Oliveira 	struct ov5647 *ov5647 = to_state(sd);
6193c2472a3SRamiro Oliveira 
6203c2472a3SRamiro Oliveira 	v4l2_async_unregister_subdev(&ov5647->sd);
6213c2472a3SRamiro Oliveira 	media_entity_cleanup(&ov5647->sd.entity);
6223c2472a3SRamiro Oliveira 	v4l2_device_unregister_subdev(sd);
6233c2472a3SRamiro Oliveira 	mutex_destroy(&ov5647->lock);
6243c2472a3SRamiro Oliveira 
6253c2472a3SRamiro Oliveira 	return 0;
6263c2472a3SRamiro Oliveira }
6273c2472a3SRamiro Oliveira 
6283c2472a3SRamiro Oliveira static const struct i2c_device_id ov5647_id[] = {
6293c2472a3SRamiro Oliveira 	{ "ov5647", 0 },
6303c2472a3SRamiro Oliveira 	{ }
6313c2472a3SRamiro Oliveira };
6323c2472a3SRamiro Oliveira MODULE_DEVICE_TABLE(i2c, ov5647_id);
6333c2472a3SRamiro Oliveira 
6343c2472a3SRamiro Oliveira #if IS_ENABLED(CONFIG_OF)
6353c2472a3SRamiro Oliveira static const struct of_device_id ov5647_of_match[] = {
6363c2472a3SRamiro Oliveira 	{ .compatible = "ovti,ov5647" },
6373c2472a3SRamiro Oliveira 	{ /* sentinel */ },
6383c2472a3SRamiro Oliveira };
6393c2472a3SRamiro Oliveira MODULE_DEVICE_TABLE(of, ov5647_of_match);
6403c2472a3SRamiro Oliveira #endif
6413c2472a3SRamiro Oliveira 
6423c2472a3SRamiro Oliveira static struct i2c_driver ov5647_driver = {
6433c2472a3SRamiro Oliveira 	.driver = {
6443c2472a3SRamiro Oliveira 		.of_match_table = of_match_ptr(ov5647_of_match),
6453c2472a3SRamiro Oliveira 		.name	= SENSOR_NAME,
6463c2472a3SRamiro Oliveira 	},
6473c2472a3SRamiro Oliveira 	.probe		= ov5647_probe,
6483c2472a3SRamiro Oliveira 	.remove		= ov5647_remove,
6493c2472a3SRamiro Oliveira 	.id_table	= ov5647_id,
6503c2472a3SRamiro Oliveira };
6513c2472a3SRamiro Oliveira 
6523c2472a3SRamiro Oliveira module_i2c_driver(ov5647_driver);
6533c2472a3SRamiro Oliveira 
6543c2472a3SRamiro Oliveira MODULE_AUTHOR("Ramiro Oliveira <roliveir@synopsys.com>");
6553c2472a3SRamiro Oliveira MODULE_DESCRIPTION("A low-level driver for OmniVision ov5647 sensors");
6563c2472a3SRamiro Oliveira MODULE_LICENSE("GPL v2");
657