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