aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>2019-05-17 19:29:53 +0530
committerManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>2019-05-17 19:36:54 +0530
commit6fd8b9ca2df0f0969344d68fa29f3777f8c4160a (patch)
tree46d32e1dd660360f596247908bac2b45e29d83f0
parentc934510f775f27c88675e5b2335650596ce4d8d9 (diff)
camera fixrock960_isp
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi44
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399.dtsi6
-rw-r--r--drivers/iommu/rockchip-iommu.c2
-rw-r--r--drivers/media/i2c/ov5645.c1263
-rw-r--r--drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c50
5 files changed, 708 insertions, 657 deletions
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi
index 7a9d7320654b..9720c71aa348 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi
@@ -363,21 +363,25 @@
&i2c2 {
status = "okay";
+ clock-frequency = <400000>;
+ i2c-scl-rising-time-ns = <168>;
+ i2c-scl-falling-time-ns = <4>;
+ status = "okay";
camera0: ov5645@3c {
compatible = "ovti,ov5645";
reg = <0x3c>;
clocks = <&cru SCLK_CIF_OUT>;
- clock-names = "xclk";
- clock-frequency = <24000000>;
+ clock-names = "xvclk";
+// clock-frequency = <24000000>;
vdddo-supply = <&camera_vdddo_1v8>;
vdda-supply = <&camera_vdda_2v8>;
vddd-supply = <&camera_vddd_1v5>;
pinctrl-0 = <&cam0_reset_pins &cam0_en_pins>;
pinctrl-names = "default";
- enable-gpios = <&gpio4 RK_PA4 GPIO_ACTIVE_HIGH>;
- reset-gpios = <&gpio3 RK_PD5 GPIO_ACTIVE_LOW>;
+ reset-gpios = <&gpio3 RK_PD5 GPIO_ACTIVE_HIGH>;
+ pwdn-gpios = <&gpio4 RK_PA4 GPIO_ACTIVE_HIGH>;
port {
ov5645_0_out: endpoint {
@@ -399,29 +403,6 @@
&i2c6 {
status = "okay";
-
- camera1: ov5645@3c {
- compatible = "ovti,ov5645";
- reg = <0x3c>;
- clocks = <&cru SCLK_CIF_OUT>;
- clock-names = "xclk";
- clock-frequency = <24000000>;
-
- vdddo-supply = <&camera_vdddo_1v8>;
- vdda-supply = <&camera_vdda_2v8>;
- vddd-supply = <&camera_vddd_1v5>;
- pinctrl-0 = <&cam1_reset_pins &cam1_en_pins>;
- pinctrl-names = "default";
- enable-gpios = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>;
- reset-gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>;
-
- port {
- ov5645_1_out: endpoint {
- remote-endpoint = <&ov5645_1_in>;
- data-lanes = <1 2>;
- };
- };
- };
};
&i2s2 {
@@ -764,15 +745,6 @@
port@1 {
reg = <1>;
- ov5645_1_in: endpoint {
- remote-endpoint = <&ov5645_1_out>;
- clock-lanes = <1>;
- data-lanes = <0 2>;
- };
- };
-
- port@2 {
- reg = <2>;
dphy_rx0_out: endpoint {
remote-endpoint = <&isp_mipi_in>;
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index d627217b5cbb..9b897c57fcb7 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1723,8 +1723,10 @@
reg = <0x0 0xff914000 0x0 0x100>, <0x0 0xff915000 0x0 0x100>;
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "isp0_mmu";
- clocks = <&cru ACLK_ISP0_NOC>, <&cru HCLK_ISP0_NOC>;
- clock-names = "aclk", "iface";
+ clocks = <&cru ACLK_ISP0_NOC>, <&cru HCLK_ISP0_NOC>,
+ <&cru ACLK_ISP0_WRAPPER>, <&cru HCLK_ISP0_WRAPPER>;
+ clock-names = "aclk", "iface", "aclk_wrapper", "iface_wrapper";
+ power-domains = <&power RK3399_PD_ISP0>;
#iommu-cells = <0>;
rockchip,disable-mmu-reset;
status = "disabled";
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 77d4bd93fe4b..41d21a8cab1b 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -96,7 +96,7 @@ struct rk_iommu_domain {
/* list of clocks required by IOMMU */
static const char * const rk_iommu_clocks[] = {
- "aclk", "iface",
+ "aclk", "iface", "aclk_wrapper", "iface_wrapper",
};
struct rk_iommu {
diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c
index 785f326ac519..6b688d0114a5 100644
--- a/drivers/media/i2c/ov5645.c
+++ b/drivers/media/i2c/ov5645.c
@@ -1,58 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * Driver for the OV5645 camera sensor.
+ * ov5645 driver
*
- * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
- * Copyright (C) 2015 By Tech Design S.L. All Rights Reserved.
- * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * Based on:
- * - the OV5645 driver from QC msm-3.10 kernel on codeaurora.org:
- * https://us.codeaurora.org/cgit/quic/la/kernel/msm-3.10/tree/drivers/
- * media/platform/msm/camera_v2/sensor/ov5645.c?h=LA.BR.1.2.4_rb1.41
- * - the OV5640 driver posted on linux-media:
- * https://www.mail-archive.com/linux-media%40vger.kernel.org/msg92671.html
- */
-
-/*
- * 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; either version 2 of the License, or
- * (at your option) any later version.
-
- * 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.
+ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
*/
-#include <linux/bitops.h>
#include <linux/clk.h>
-#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
-#include <linux/init.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-#include <linux/types.h>
+#include <linux/sysfs.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
+#include <linux/pinctrl/consumer.h>
+
+#ifndef V4L2_CID_DIGITAL_GAIN
+#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
+#endif
+
+#define OV5645_XVCLK_FREQ 24000000
+
+#define OV5645_SYSTEM_CTRL0 0x3008
+#define OV5645_SYSTEM_CTRL0_START 0x02
+#define OV5645_SYSTEM_CTRL0_STOP 0x42
+
+#define CHIP_ID 0x005645
+#define OV5645_REG_CHIP_ID 0x300a
+
+#define REG_NULL 0xFFFF
+
+#define OV5645_REG_VALUE_08BIT 1
+#define OV5645_REG_VALUE_16BIT 2
+#define OV5645_REG_VALUE_24BIT 3
+
+
+#define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default"
+#define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep"
-#define OV5645_VOLTAGE_ANALOG 2800000
-#define OV5645_VOLTAGE_DIGITAL_CORE 1500000
-#define OV5645_VOLTAGE_DIGITAL_IO 1800000
-
-#define OV5645_SYSTEM_CTRL0 0x3008
-#define OV5645_SYSTEM_CTRL0_START 0x02
-#define OV5645_SYSTEM_CTRL0_STOP 0x42
-#define OV5645_CHIP_ID_HIGH 0x300a
-#define OV5645_CHIP_ID_HIGH_BYTE 0x56
-#define OV5645_CHIP_ID_LOW 0x300b
-#define OV5645_CHIP_ID_LOW_BYTE 0x45
#define OV5645_AWB_MANUAL_CONTROL 0x3406
#define OV5645_AWB_MANUAL_ENABLE BIT(0)
#define OV5645_AEC_PK_MANUAL 0x3503
@@ -70,58 +60,70 @@
#define OV5645_SDE_SAT_U 0x5583
#define OV5645_SDE_SAT_V 0x5584
-struct reg_value {
- u16 reg;
+static const struct regval *ov5645_global_regs;
+
+static const char * const ov5645_supply_names[] = {
+ "avdd", /* Analog power */
+ "dovdd", /* Digital I/O power */
+ "dvdd", /* Digital core power */
+};
+
+#define OV5645_NUM_SUPPLIES ARRAY_SIZE(ov5645_supply_names)
+
+struct regval {
+ u16 addr;
u8 val;
};
-struct ov5645_mode_info {
+struct ov5645_mode {
u32 width;
u32 height;
- const struct reg_value *data;
+ const struct regval *reg_list;
u32 data_size;
u32 pixel_clock;
u32 link_freq;
};
struct ov5645 {
- struct i2c_client *i2c_client;
+ struct i2c_client *client;
+ struct clk *xvclk;
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *pwdn_gpio;
+ struct regulator_bulk_data supplies[OV5645_NUM_SUPPLIES];
+
struct device *dev;
- struct v4l2_subdev sd;
- struct media_pad pad;
- struct v4l2_fwnode_endpoint ep;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_default;
+ struct pinctrl_state *pins_sleep;
struct v4l2_mbus_framefmt fmt;
+ struct v4l2_subdev subdev;
struct v4l2_rect crop;
- struct clk *xclk;
-
- struct regulator *io_regulator;
- struct regulator *core_regulator;
- struct regulator *analog_regulator;
-
- const struct ov5645_mode_info *current_mode;
-
- struct v4l2_ctrl_handler ctrls;
+ struct media_pad pad;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *anal_gain;
+ struct v4l2_ctrl *digi_gain;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *test_pattern;
+ struct mutex mutex;
+ bool streaming;
+ const struct ov5645_mode *cur_mode;
struct v4l2_ctrl *pixel_clock;
struct v4l2_ctrl *link_freq;
- /* Cached register values */
- u8 aec_pk_manual;
- u8 timing_tc_reg20;
- u8 timing_tc_reg21;
-
- struct mutex power_lock; /* lock to protect power state */
- int power_count;
-
- struct gpio_desc *enable_gpio;
- struct gpio_desc *rst_gpio;
+/* Cached register values */
+ u32 aec_pk_manual;
+ u32 timing_tc_reg20;
+ u32 timing_tc_reg21;
};
-static inline struct ov5645 *to_ov5645(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct ov5645, sd);
-}
+#define to_ov5645(sd) container_of(sd, struct ov5645, subdev)
-static const struct reg_value ov5645_global_init_setting[] = {
+/*
+ * Xclk 24Mhz
+ */
+static const struct regval ov5645_global_regs_r1a[] = {
{ 0x3103, 0x11 },
{ 0x3008, 0x82 },
{ 0x3008, 0x42 },
@@ -358,10 +360,12 @@ static const struct reg_value ov5645_global_init_setting[] = {
{ 0x3a1f, 0x14 },
{ 0x0601, 0x02 },
{ 0x3008, 0x42 },
- { 0x3008, 0x02 }
+ { 0x3008, 0x02 },
+ {REG_NULL, 0x00},
};
-static const struct reg_value ov5645_setting_sxga[] = {
+
+static const struct regval ov5645_setting_sxga[] = {
{ 0x3612, 0xa9 },
{ 0x3614, 0x50 },
{ 0x3618, 0x00 },
@@ -406,10 +410,11 @@ static const struct reg_value ov5645_setting_sxga[] = {
{ 0x4004, 0x02 },
{ 0x4005, 0x18 },
{ 0x4300, 0x32 },
- { 0x4202, 0x00 }
+ { 0x4202, 0x00 },
+ {REG_NULL, 0x00},
};
-static const struct reg_value ov5645_setting_1080p[] = {
+static const struct regval ov5645_setting_1080p[] = {
{ 0x3612, 0xab },
{ 0x3614, 0x50 },
{ 0x3618, 0x04 },
@@ -456,10 +461,11 @@ static const struct reg_value ov5645_setting_1080p[] = {
{ 0x4005, 0x18 },
{ 0x4300, 0x32 },
{ 0x4202, 0x00 },
- { 0x4837, 0x0b }
+ { 0x4837, 0x0b },
+ {REG_NULL, 0x00},
};
-static const struct reg_value ov5645_setting_full[] = {
+static const struct regval ov5645_setting_full[] = {
{ 0x3612, 0xab },
{ 0x3614, 0x50 },
{ 0x3618, 0x04 },
@@ -506,19 +512,15 @@ static const struct reg_value ov5645_setting_full[] = {
{ 0x4005, 0x18 },
{ 0x4300, 0x32 },
{ 0x4837, 0x0b },
- { 0x4202, 0x00 }
-};
-
-static const s64 link_freq[] = {
- 224000000,
- 336000000
+ { 0x4202, 0x00 },
+ {REG_NULL, 0x00},
};
-static const struct ov5645_mode_info ov5645_mode_info_data[] = {
+static const struct ov5645_mode supported_modes[] = {
{
.width = 1280,
.height = 960,
- .data = ov5645_setting_sxga,
+ .reg_list = ov5645_setting_sxga,
.data_size = ARRAY_SIZE(ov5645_setting_sxga),
.pixel_clock = 112000000,
.link_freq = 0 /* an index in link_freq[] */
@@ -526,7 +528,7 @@ static const struct ov5645_mode_info ov5645_mode_info_data[] = {
{
.width = 1920,
.height = 1080,
- .data = ov5645_setting_1080p,
+ .reg_list = ov5645_setting_1080p,
.data_size = ARRAY_SIZE(ov5645_setting_1080p),
.pixel_clock = 168000000,
.link_freq = 1 /* an index in link_freq[] */
@@ -534,102 +536,92 @@ static const struct ov5645_mode_info ov5645_mode_info_data[] = {
{
.width = 2592,
.height = 1944,
- .data = ov5645_setting_full,
+ .reg_list = ov5645_setting_full,
.data_size = ARRAY_SIZE(ov5645_setting_full),
.pixel_clock = 168000000,
.link_freq = 1 /* an index in link_freq[] */
},
};
-static int ov5645_regulators_enable(struct ov5645 *ov5645)
+static const s64 link_freq_menu_items[] = {
+ 224000000,
+ 336000000
+};
+
+/* Write registers up to 4 at a time */
+static int ov5645_write_reg(struct i2c_client *client, u16 reg,
+ u32 len, u32 val)
{
- int ret;
+ u32 buf_i, val_i;
+ u8 buf[6];
+ u8 *val_p;
+ __be32 val_be;
- ret = regulator_enable(ov5645->io_regulator);
- if (ret < 0) {
- dev_err(ov5645->dev, "set io voltage failed\n");
- return ret;
- }
+ if (len > 4)
+ return -EINVAL;
- ret = regulator_enable(ov5645->analog_regulator);
- if (ret) {
- dev_err(ov5645->dev, "set analog voltage failed\n");
- goto err_disable_io;
- }
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
- ret = regulator_enable(ov5645->core_regulator);
- if (ret) {
- dev_err(ov5645->dev, "set core voltage failed\n");
- goto err_disable_analog;
- }
+ val_be = cpu_to_be32(val);
+ val_p = (u8 *)&val_be;
+ buf_i = 2;
+ val_i = 4 - len;
- return 0;
+ while (val_i < 4)
+ buf[buf_i++] = val_p[val_i++];
-err_disable_analog:
- regulator_disable(ov5645->analog_regulator);
-err_disable_io:
- regulator_disable(ov5645->io_regulator);
+ if (i2c_master_send(client, buf, len + 2) != len + 2)
+ return -EIO;
- return ret;
+ return 0;
}
-static void ov5645_regulators_disable(struct ov5645 *ov5645)
+static int ov5645_write_array(struct i2c_client *client,
+ const struct regval *regs)
{
- int ret;
-
- ret = regulator_disable(ov5645->core_regulator);
- if (ret < 0)
- dev_err(ov5645->dev, "core regulator disable failed\n");
+ u32 i;
+ int ret = 0;
- ret = regulator_disable(ov5645->analog_regulator);
- if (ret < 0)
- dev_err(ov5645->dev, "analog regulator disable failed\n");
+ for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
+ ret = ov5645_write_reg(client, regs[i].addr,
+ OV5645_REG_VALUE_08BIT,
+ regs[i].val);
- ret = regulator_disable(ov5645->io_regulator);
- if (ret < 0)
- dev_err(ov5645->dev, "io regulator disable failed\n");
+ return ret;
}
-static int ov5645_write_reg(struct ov5645 *ov5645, u16 reg, u8 val)
+/* Read registers up to 4 at a time */
+static int ov5645_read_reg(struct i2c_client *client, u16 reg,
+ unsigned int len, u32 *val)
{
- u8 regbuf[3];
+ struct i2c_msg msgs[2];
+ u8 *data_be_p;
+ __be32 data_be = 0;
+ __be16 reg_addr_be = cpu_to_be16(reg);
int ret;
- regbuf[0] = reg >> 8;
- regbuf[1] = reg & 0xff;
- regbuf[2] = val;
+ if (len > 4 || !len)
+ return -EINVAL;
- ret = i2c_master_send(ov5645->i2c_client, regbuf, 3);
- if (ret < 0) {
- dev_err(ov5645->dev, "%s: write reg error %d: reg=%x, val=%x\n",
- __func__, ret, reg, val);
- return ret;
- }
+ data_be_p = (u8 *)&data_be;
+ /* Write register address */
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 2;
+ msgs[0].buf = (u8 *)&reg_addr_be;
- return 0;
-}
-
-static int ov5645_read_reg(struct ov5645 *ov5645, u16 reg, u8 *val)
-{
- u8 regbuf[2];
- int ret;
+ /* Read data from register */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = &data_be_p[4 - len];
- regbuf[0] = reg >> 8;
- regbuf[1] = reg & 0xff;
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
- ret = i2c_master_send(ov5645->i2c_client, regbuf, 2);
- if (ret < 0) {
- dev_err(ov5645->dev, "%s: write reg error %d: reg=%x\n",
- __func__, ret, reg);
- return ret;
- }
-
- ret = i2c_master_recv(ov5645->i2c_client, val, 1);
- if (ret < 0) {
- dev_err(ov5645->dev, "%s: read reg error %d: reg=%x\n",
- __func__, ret, reg);
- return ret;
- }
+ *val = be32_to_cpu(data_be);
return 0;
}
@@ -644,7 +636,7 @@ static int ov5645_set_aec_mode(struct ov5645 *ov5645, u32 mode)
else /* V4L2_EXPOSURE_MANUAL */
val |= OV5645_AEC_MANUAL_ENABLE;
- ret = ov5645_write_reg(ov5645, OV5645_AEC_PK_MANUAL, val);
+ ret = ov5645_write_reg(ov5645->client, OV5645_AEC_PK_MANUAL,OV5645_REG_VALUE_08BIT,(u32)val);
if (!ret)
ov5645->aec_pk_manual = val;
@@ -661,121 +653,404 @@ static int ov5645_set_agc_mode(struct ov5645 *ov5645, u32 enable)
else
val |= OV5645_AGC_MANUAL_ENABLE;
- ret = ov5645_write_reg(ov5645, OV5645_AEC_PK_MANUAL, val);
+ ret = ov5645_write_reg(ov5645->client, OV5645_AEC_PK_MANUAL, OV5645_REG_VALUE_08BIT,(u32)val);
if (!ret)
ov5645->aec_pk_manual = val;
return ret;
}
-static int ov5645_set_register_array(struct ov5645 *ov5645,
- const struct reg_value *settings,
- unsigned int num_settings)
+static struct v4l2_rect *
+__ov5645_get_pad_crop(struct ov5645 *ov5645, struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(&ov5645->subdev, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &ov5645->crop;
+ default:
+ return NULL;
+ }
+
+}
+
+static struct v4l2_mbus_framefmt *
+__ov5645_get_pad_format(struct ov5645 *ov5645,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad,
+ enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&ov5645->subdev, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &ov5645->fmt;
+ default:
+ return NULL;
+ }
+}
+
+static int ov5645_get_reso_dist(const struct ov5645_mode *mode,
+ struct v4l2_mbus_framefmt *framefmt)
+{
+ return abs(mode->width - framefmt->width) +
+ abs(mode->height - framefmt->height);
+}
+
+static const struct ov5645_mode *
+ov5645_find_best_fit(struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *framefmt = &fmt->format;
+ int dist;
+ int cur_best_fit = 0;
+ int cur_best_fit_dist = -1;
unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
+ dist = ov5645_get_reso_dist(&supported_modes[i], framefmt);
+ if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
+ cur_best_fit_dist = dist;
+ cur_best_fit = i;
+ }
+ }
+
+ return &supported_modes[cur_best_fit];
+}
+
+static int ov5645_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov5645 *ov5645 = to_ov5645(sd);
+ struct v4l2_mbus_framefmt *__format;
+ struct v4l2_rect *__crop;
+ const struct ov5645_mode *new_mode;
int ret;
- for (i = 0; i < num_settings; ++i, ++settings) {
- ret = ov5645_write_reg(ov5645, settings->reg, settings->val);
+ __crop = __ov5645_get_pad_crop(ov5645, cfg, fmt->pad,
+ fmt->which);
+
+ new_mode = ov5645_find_best_fit(fmt);
+
+ __crop->width = new_mode->width;
+ __crop->height = new_mode->height;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ ret = v4l2_ctrl_s_ctrl_int64(ov5645->pixel_clock,
+ new_mode->pixel_clock);
if (ret < 0)
return ret;
+
+ ret = v4l2_ctrl_s_ctrl(ov5645->link_freq,
+ new_mode->link_freq);
+ if (ret < 0)
+ return ret;
+
+ ov5645->cur_mode = new_mode;
}
+ __format = __ov5645_get_pad_format(ov5645, cfg, fmt->pad,
+ fmt->which);
+ __format->width = __crop->width;
+ __format->height = __crop->height;
+ __format->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ __format->field = V4L2_FIELD_NONE;
+ __format->colorspace = V4L2_COLORSPACE_SRGB;
+
+ fmt->format = *__format;
+
return 0;
}
-static int ov5645_set_power_on(struct ov5645 *ov5645)
+static int ov5645_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+
+ struct ov5645 *ov5645 = to_ov5645(sd);
+ const struct ov5645_mode *mode = ov5645->cur_mode;
+
+ mutex_lock(&ov5645->mutex);
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ } else {
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.code = MEDIA_BUS_FMT_UYVY8_2X8;//MEDIA_BUS_FMT_SBGGR10_1X10;
+ fmt->format.field = V4L2_FIELD_NONE;
+ }
+ mutex_unlock(&ov5645->mutex);
+
+ return 0;
+}
+
+static int ov5645_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index > 0)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_UYVY8_2X8;
+
+ return 0;
+}
+
+static int ov5645_enum_frame_sizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->code != MEDIA_BUS_FMT_UYVY8_2X8)
+ return -EINVAL;
+
+ if (fse->index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ fse->min_width = supported_modes[fse->index].width;
+ fse->max_width = supported_modes[fse->index].width;
+ fse->min_height = supported_modes[fse->index].height;
+ fse->max_height = supported_modes[fse->index].height;
+
+ return 0;
+}
+static int ov5645_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct ov5645 *ov5645 = to_ov5645(sd);
+ int ret = 0;
+ struct i2c_client *client = ov5645->client;
+
+ mutex_lock(&ov5645->mutex);
+ on = !!on;
+
+ if(on == ov5645->streaming)
+ goto unlock_and_return;
+
+ if (on) {
+ ret = pm_runtime_get_sync(&client->dev);
+
+ if(ret < 0) {
+ pm_runtime_put_noidle(&client->dev);
+ goto unlock_and_return;
+ }
+
+ ret = ov5645_write_array(ov5645->client, ov5645_global_regs_r1a);
+ if (ret){
+
+ pm_runtime_put(&client->dev);
+ goto unlock_and_return;
+ }
+ ret = ov5645_write_array(ov5645->client,
+ ov5645->cur_mode->reg_list);
+ if (ret < 0) {
+ dev_err(ov5645->dev, "could not set mode %dx%d\n",
+ ov5645->cur_mode->width,
+ ov5645->cur_mode->height);
+ pm_runtime_put(&client->dev);
+ goto unlock_and_return;
+ }
+ mutex_unlock(&ov5645->mutex);
+ ret = v4l2_ctrl_handler_setup(&ov5645->ctrl_handler);
+ mutex_lock(&ov5645->mutex);
+ if (ret < 0) {
+ dev_err(ov5645->dev, "could not sync v4l2 controls\n");
+ pm_runtime_put(&client->dev);
+ goto unlock_and_return;
+ }
+ ret = ov5645_write_reg(ov5645->client, OV5645_SYSTEM_CTRL0,
+ OV5645_REG_VALUE_08BIT,
+ OV5645_SYSTEM_CTRL0_START);
+ if (ret < 0){
+ pm_runtime_put(&client->dev);
+ goto unlock_and_return;
+ }
+ } else {
+ ov5645_write_reg(ov5645->client, OV5645_SYSTEM_CTRL0,
+ OV5645_REG_VALUE_08BIT,
+ OV5645_SYSTEM_CTRL0_STOP);
+ pm_runtime_put(&client->dev);
+ }
+
+ ov5645->streaming = on;
+
+unlock_and_return:
+ mutex_unlock(&ov5645->mutex);
+
+ return ret;
+
+}
+
+static int __ov5645_power_on(struct ov5645 *ov5645)
{
int ret;
+ struct device *dev = &ov5645->client->dev;
- ret = ov5645_regulators_enable(ov5645);
+ if (!IS_ERR_OR_NULL(ov5645->pins_default)) {
+ ret = pinctrl_select_state(ov5645->pinctrl,
+ ov5645->pins_default);
+ if (ret < 0)
+ dev_err(dev, "could not set pins\n");
+ }
+
+ ret = clk_prepare_enable(ov5645->xvclk);
if (ret < 0) {
+ dev_err(dev, "Failed to enable xvclk\n");
return ret;
}
- ret = clk_prepare_enable(ov5645->xclk);
+ if (!IS_ERR(ov5645->reset_gpio))
+ gpiod_set_value_cansleep(ov5645->reset_gpio, 0);
+
+ ret = regulator_bulk_enable(OV5645_NUM_SUPPLIES, ov5645->supplies);
if (ret < 0) {
- dev_err(ov5645->dev, "clk prepare enable failed\n");
- ov5645_regulators_disable(ov5645);
- return ret;
+ dev_err(dev, "Failed to enable regulators\n");
+ goto disable_clk;
}
usleep_range(5000, 15000);
- gpiod_set_value_cansleep(ov5645->enable_gpio, 1);
+ if (!IS_ERR(ov5645->reset_gpio))
+ gpiod_set_value_cansleep(ov5645->reset_gpio, 1);
usleep_range(1000, 2000);
- gpiod_set_value_cansleep(ov5645->rst_gpio, 0);
+ if (!IS_ERR(ov5645->pwdn_gpio))
+ gpiod_set_value_cansleep(ov5645->pwdn_gpio, 1);
msleep(20);
return 0;
+
+disable_clk:
+ clk_disable_unprepare(ov5645->xvclk);
+
+ return ret;
}
-static void ov5645_set_power_off(struct ov5645 *ov5645)
+static void __ov5645_power_off(struct ov5645 *ov5645)
{
- gpiod_set_value_cansleep(ov5645->rst_gpio, 1);
- gpiod_set_value_cansleep(ov5645->enable_gpio, 0);
- clk_disable_unprepare(ov5645->xclk);
- ov5645_regulators_disable(ov5645);
+ int ret;
+ struct device *dev = &ov5645->client->dev;
+
+ if (!IS_ERR(ov5645->pwdn_gpio))
+ gpiod_set_value_cansleep(ov5645->pwdn_gpio, 0);
+ clk_disable_unprepare(ov5645->xvclk);
+ if (!IS_ERR(ov5645->reset_gpio))
+ gpiod_set_value_cansleep(ov5645->reset_gpio, 0);
+ if (!IS_ERR_OR_NULL(ov5645->pins_sleep)) {
+ ret = pinctrl_select_state(ov5645->pinctrl,
+ ov5645->pins_sleep);
+ if (ret < 0)
+ dev_dbg(dev, "could not set pins\n");
+ }
+ regulator_bulk_disable(OV5645_NUM_SUPPLIES, ov5645->supplies);
}
-static int ov5645_s_power(struct v4l2_subdev *sd, int on)
+static int ov5645_runtime_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct ov5645 *ov5645 = to_ov5645(sd);
- int ret = 0;
+
+ return __ov5645_power_on(ov5645);
+}
- mutex_lock(&ov5645->power_lock);
-
- /* If the power count is modified from 0 to != 0 or from != 0 to 0,
- * update the power state.
- */
- if (ov5645->power_count == !on) {
- if (on) {
- ret = ov5645_set_power_on(ov5645);
- if (ret < 0)
- goto exit;
-
- ret = ov5645_set_register_array(ov5645,
- ov5645_global_init_setting,
- ARRAY_SIZE(ov5645_global_init_setting));
- if (ret < 0) {
- dev_err(ov5645->dev,
- "could not set init registers\n");
- ov5645_set_power_off(ov5645);
- goto exit;
- }
-
- ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0,
- OV5645_SYSTEM_CTRL0_STOP);
- if (ret < 0) {
- ov5645_set_power_off(ov5645);
- goto exit;
- }
- } else {
- ov5645_set_power_off(ov5645);
- }
- }
+static int ov5645_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5645 *ov5645 = to_ov5645(sd);
+
+ __ov5645_power_off(ov5645);
+
+ return 0;
+}
- /* Update the power count. */
- ov5645->power_count += on ? 1 : -1;
- WARN_ON(ov5645->power_count < 0);
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+static int ov5645_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct ov5645 *ov5645 = to_ov5645(sd);
+ struct v4l2_mbus_framefmt *try_fmt =
+ v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ const struct ov5645_mode *def_mode = &supported_modes[0];
+
+ mutex_lock(&ov5645->mutex);
+ /* Initialize try_fmt */
+ try_fmt->width = def_mode->width;
+ try_fmt->height = def_mode->height;
+ try_fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;//MEDIA_BUS_FMT_SBGGR10_1X10;
+ try_fmt->field = V4L2_FIELD_NONE;
+
+ mutex_unlock(&ov5645->mutex);
+ /* No crop or compose */
-exit:
- mutex_unlock(&ov5645->power_lock);
+ return 0;
+}
+#endif
- return ret;
+static const struct dev_pm_ops ov5645_pm_ops = {
+ SET_RUNTIME_PM_OPS(ov5645_runtime_suspend,
+ ov5645_runtime_resume, NULL)
+};
+
+static const struct v4l2_subdev_internal_ops ov5645_internal_ops = {
+ .open = ov5645_open,
+};
+
+static const struct v4l2_subdev_video_ops ov5645_video_ops = {
+ .s_stream = ov5645_s_stream,
+};
+#if 0
+static int ov5645_entity_init_cfg(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg)
+{
+ struct v4l2_subdev_format fmt = { 0 };
+
+ fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt.format.width = 1920;
+ fmt.format.height = 1080;
+
+ ov5645_set_fmt(subdev, cfg, &fmt);
+
+ return 0;
}
+#endif
+static int ov5645_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct ov5645 *ov5645 = to_ov5645(sd);
+
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ sel->r = *__ov5645_get_pad_crop(ov5645, cfg, sel->pad,
+ sel->which);
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops ov5645_pad_ops = {
+// .init_cfg = ov5645_entity_init_cfg,
+ .enum_mbus_code = ov5645_enum_mbus_code,
+ .enum_frame_size = ov5645_enum_frame_sizes,
+ .get_fmt = ov5645_get_fmt,
+ .set_fmt = ov5645_set_fmt,
+ .get_selection = ov5645_get_selection,
+};
+
+static const struct v4l2_subdev_ops ov5645_subdev_ops = {
+ .video = &ov5645_video_ops,
+ .pad = &ov5645_pad_ops,
+};
static int ov5645_set_saturation(struct ov5645 *ov5645, s32 value)
{
u32 reg_value = (value * 0x10) + 0x40;
int ret;
-
- ret = ov5645_write_reg(ov5645, OV5645_SDE_SAT_U, reg_value);
+ ret = ov5645_write_reg(ov5645->client, OV5645_SDE_SAT_U, OV5645_REG_VALUE_08BIT,reg_value);
if (ret < 0)
+ {
return ret;
-
- return ov5645_write_reg(ov5645, OV5645_SDE_SAT_V, reg_value);
+ }
+ return ov5645_write_reg(ov5645->client, OV5645_SDE_SAT_V,OV5645_REG_VALUE_08BIT, reg_value);
}
static int ov5645_set_hflip(struct ov5645 *ov5645, s32 value)
@@ -788,7 +1063,7 @@ static int ov5645_set_hflip(struct ov5645 *ov5645, s32 value)
else
val |= (OV5645_SENSOR_MIRROR);
- ret = ov5645_write_reg(ov5645, OV5645_TIMING_TC_REG21, val);
+ ret = ov5645_write_reg(ov5645->client, OV5645_TIMING_TC_REG21,OV5645_REG_VALUE_08BIT, val);
if (!ret)
ov5645->timing_tc_reg21 = val;
@@ -805,7 +1080,7 @@ static int ov5645_set_vflip(struct ov5645 *ov5645, s32 value)
else
val &= ~(OV5645_SENSOR_VFLIP | OV5645_ISP_VFLIP);
- ret = ov5645_write_reg(ov5645, OV5645_TIMING_TC_REG20, val);
+ ret = ov5645_write_reg(ov5645->client, OV5645_TIMING_TC_REG20,OV5645_REG_VALUE_08BIT, val);
if (!ret)
ov5645->timing_tc_reg20 = val;
@@ -821,7 +1096,7 @@ static int ov5645_set_test_pattern(struct ov5645 *ov5645, s32 value)
val |= OV5645_TEST_PATTERN_ENABLE;
}
- return ov5645_write_reg(ov5645, OV5645_PRE_ISP_TEST_SETTING_1, val);
+ return ov5645_write_reg(ov5645->client, OV5645_PRE_ISP_TEST_SETTING_1,OV5645_REG_VALUE_08BIT, val);
}
static const char * const ov5645_test_pattern_menu[] = {
@@ -831,7 +1106,7 @@ static const char * const ov5645_test_pattern_menu[] = {
"Color Square",
"Black Image",
};
-
+
static int ov5645_set_awb(struct ov5645 *ov5645, s32 enable_auto)
{
u8 val = 0;
@@ -839,24 +1114,22 @@ static int ov5645_set_awb(struct ov5645 *ov5645, s32 enable_auto)
if (!enable_auto)
val = OV5645_AWB_MANUAL_ENABLE;
- return ov5645_write_reg(ov5645, OV5645_AWB_MANUAL_CONTROL, val);
+ return ov5645_write_reg(ov5645->client, OV5645_AWB_MANUAL_CONTROL,OV5645_REG_VALUE_08BIT, val);
}
-static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl)
+static int ov5645_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct ov5645 *ov5645 = container_of(ctrl->handler,
- struct ov5645, ctrls);
- int ret;
+ struct ov5645, ctrl_handler);
+ struct i2c_client *client = ov5645->client;
+ int ret = 0;
- mutex_lock(&ov5645->power_lock);
- if (!ov5645->power_count) {
- mutex_unlock(&ov5645->power_lock);
+ if (pm_runtime_get(&client->dev) <= 0)
return 0;
- }
switch (ctrl->id) {
case V4L2_CID_SATURATION:
- ret = ov5645_set_saturation(ov5645, ctrl->val);
+ ret = ov5645_set_saturation(ov5645, ctrl->val);
break;
case V4L2_CID_AUTO_WHITE_BALANCE:
ret = ov5645_set_awb(ov5645, ctrl->val);
@@ -880,455 +1153,210 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl)
ret = -EINVAL;
break;
}
-
- mutex_unlock(&ov5645->power_lock);
+
+ pm_runtime_put(&client->dev);
return ret;
}
static const struct v4l2_ctrl_ops ov5645_ctrl_ops = {
- .s_ctrl = ov5645_s_ctrl,
+ .s_ctrl = ov5645_set_ctrl,
};
-static int ov5645_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (code->index > 0)
- return -EINVAL;
-
- code->code = MEDIA_BUS_FMT_UYVY8_2X8;
-
- return 0;
-}
-
-static int ov5645_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- if (fse->code != MEDIA_BUS_FMT_UYVY8_2X8)
- return -EINVAL;
-
- if (fse->index >= ARRAY_SIZE(ov5645_mode_info_data))
- return -EINVAL;
-
- fse->min_width = ov5645_mode_info_data[fse->index].width;
- fse->max_width = ov5645_mode_info_data[fse->index].width;
- fse->min_height = ov5645_mode_info_data[fse->index].height;
- fse->max_height = ov5645_mode_info_data[fse->index].height;
-
- return 0;
-}
-
-static struct v4l2_mbus_framefmt *
-__ov5645_get_pad_format(struct ov5645 *ov5645,
- struct v4l2_subdev_pad_config *cfg,
- unsigned int pad,
- enum v4l2_subdev_format_whence which)
-{
- switch (which) {
- case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&ov5645->sd, cfg, pad);
- case V4L2_SUBDEV_FORMAT_ACTIVE:
- return &ov5645->fmt;
- default:
- return NULL;
- }
-}
-
-static int ov5645_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *format)
+static int ov5645_check_sensor_id(struct ov5645 *ov5645,
+ struct i2c_client *client)
{
- struct ov5645 *ov5645 = to_ov5645(sd);
-
- format->format = *__ov5645_get_pad_format(ov5645, cfg, format->pad,
- format->which);
- return 0;
-}
-
-static struct v4l2_rect *
-__ov5645_get_pad_crop(struct ov5645 *ov5645, struct v4l2_subdev_pad_config *cfg,
- unsigned int pad, enum v4l2_subdev_format_whence which)
-{
- switch (which) {
- case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&ov5645->sd, cfg, pad);
- case V4L2_SUBDEV_FORMAT_ACTIVE:
- return &ov5645->crop;
- default:
- return NULL;
- }
-}
-
-static int ov5645_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *format)
-{
- struct ov5645 *ov5645 = to_ov5645(sd);
- struct v4l2_mbus_framefmt *__format;
- struct v4l2_rect *__crop;
- const struct ov5645_mode_info *new_mode;
+ struct device *dev = &ov5645->client->dev;
+ u32 id = 0;
int ret;
- __crop = __ov5645_get_pad_crop(ov5645, cfg, format->pad,
- format->which);
-
- new_mode = v4l2_find_nearest_size(ov5645_mode_info_data,
- ARRAY_SIZE(ov5645_mode_info_data),
- width, height,
- format->format.width, format->format.height);
-
- __crop->width = new_mode->width;
- __crop->height = new_mode->height;
-
- if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- ret = v4l2_ctrl_s_ctrl_int64(ov5645->pixel_clock,
- new_mode->pixel_clock);
- if (ret < 0)
- return ret;
-
- ret = v4l2_ctrl_s_ctrl(ov5645->link_freq,
- new_mode->link_freq);
- if (ret < 0)
- return ret;
-
- ov5645->current_mode = new_mode;
+ ret = ov5645_read_reg(client, OV5645_REG_CHIP_ID,
+ OV5645_REG_VALUE_16BIT, &id);
+ if (id != CHIP_ID) {
+ dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
+ return ret;
}
- __format = __ov5645_get_pad_format(ov5645, cfg, format->pad,
- format->which);
- __format->width = __crop->width;
- __format->height = __crop->height;
- __format->code = MEDIA_BUS_FMT_UYVY8_2X8;
- __format->field = V4L2_FIELD_NONE;
- __format->colorspace = V4L2_COLORSPACE_SRGB;
-
- format->format = *__format;
+ ov5645_global_regs = ov5645_global_regs_r1a;
+
+ dev_info(dev, "Detected OV%06x sensor, REVISION 0x%x\n", CHIP_ID, id);
return 0;
}
-static int ov5645_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg)
+static int ov5645_configure_regulators(struct ov5645 *ov5645)
{
- struct v4l2_subdev_format fmt = { 0 };
-
- fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt.format.width = 1920;
- fmt.format.height = 1080;
+ unsigned int i;
- ov5645_set_format(subdev, cfg, &fmt);
+ for (i = 0; i < OV5645_NUM_SUPPLIES; i++)
+ ov5645->supplies[i].supply = ov5645_supply_names[i];
- return 0;
+ return devm_regulator_bulk_get(&ov5645->client->dev,
+ OV5645_NUM_SUPPLIES,
+ ov5645->supplies);
}
-static int ov5645_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_selection *sel)
-{
- struct ov5645 *ov5645 = to_ov5645(sd);
-
- if (sel->target != V4L2_SEL_TGT_CROP)
- return -EINVAL;
-
- sel->r = *__ov5645_get_pad_crop(ov5645, cfg, sel->pad,
- sel->which);
- return 0;
-}
-
-static int ov5645_s_stream(struct v4l2_subdev *subdev, int enable)
-{
- struct ov5645 *ov5645 = to_ov5645(subdev);
- int ret;
-
- if (enable) {
- ret = ov5645_set_register_array(ov5645,
- ov5645->current_mode->data,
- ov5645->current_mode->data_size);
- if (ret < 0) {
- dev_err(ov5645->dev, "could not set mode %dx%d\n",
- ov5645->current_mode->width,
- ov5645->current_mode->height);
- return ret;
- }
- ret = v4l2_ctrl_handler_setup(&ov5645->ctrls);
- if (ret < 0) {
- dev_err(ov5645->dev, "could not sync v4l2 controls\n");
- return ret;
- }
- ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0,
- OV5645_SYSTEM_CTRL0_START);
- if (ret < 0)
- return ret;
- } else {
- ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0,
- OV5645_SYSTEM_CTRL0_STOP);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-static const struct v4l2_subdev_core_ops ov5645_core_ops = {
- .s_power = ov5645_s_power,
-};
-
-static const struct v4l2_subdev_video_ops ov5645_video_ops = {
- .s_stream = ov5645_s_stream,
-};
-
-static const struct v4l2_subdev_pad_ops ov5645_subdev_pad_ops = {
- .init_cfg = ov5645_entity_init_cfg,
- .enum_mbus_code = ov5645_enum_mbus_code,
- .enum_frame_size = ov5645_enum_frame_size,
- .get_fmt = ov5645_get_format,
- .set_fmt = ov5645_set_format,
- .get_selection = ov5645_get_selection,
-};
-
-static const struct v4l2_subdev_ops ov5645_subdev_ops = {
- .core = &ov5645_core_ops,
- .video = &ov5645_video_ops,
- .pad = &ov5645_subdev_pad_ops,
-};
-
static int ov5645_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
- struct device_node *endpoint;
struct ov5645 *ov5645;
- u8 chip_id_high, chip_id_low;
- u32 xclk_freq;
+ struct v4l2_subdev *sd;
int ret;
- ov5645 = devm_kzalloc(dev, sizeof(struct ov5645), GFP_KERNEL);
+ ov5645 = devm_kzalloc(dev, sizeof(*ov5645), GFP_KERNEL);
if (!ov5645)
return -ENOMEM;
- ov5645->i2c_client = client;
- ov5645->dev = dev;
+ ov5645->client = client;
+ ov5645->cur_mode = &supported_modes[0];
- endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
- if (!endpoint) {
- dev_err(dev, "endpoint node not found\n");
+ ov5645->xvclk = devm_clk_get(dev, "xvclk");
+ if (IS_ERR(ov5645->xvclk)) {
+ dev_err(dev, "Failed to get xvclk\n");
return -EINVAL;
}
-
- ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint),
- &ov5645->ep);
-
- of_node_put(endpoint);
-
+ ret = clk_set_rate(ov5645->xvclk, OV5645_XVCLK_FREQ);
if (ret < 0) {
- dev_err(dev, "parsing endpoint node failed\n");
+ dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
return ret;
}
+ if (clk_get_rate(ov5645->xvclk) != OV5645_XVCLK_FREQ)
+ dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
- if (ov5645->ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
- dev_err(dev, "invalid bus type, must be CSI2\n");
- return -EINVAL;
- }
-
- /* get system clock (xclk) */
- ov5645->xclk = devm_clk_get(dev, "xclk");
- if (IS_ERR(ov5645->xclk)) {
- dev_err(dev, "could not get xclk");
- return PTR_ERR(ov5645->xclk);
- }
-
- ret = of_property_read_u32(dev->of_node, "clock-frequency", &xclk_freq);
- if (ret) {
- dev_err(dev, "could not get xclk frequency\n");
- return ret;
- }
+ ov5645->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ov5645->reset_gpio))
+ dev_warn(dev, "Failed to get reset-gpios\n");
- /* external clock must be 24MHz, allow 1% tolerance */
- if (xclk_freq < 23760000 || xclk_freq > 24240000) {
- dev_err(dev, "external clock frequency %u is not supported\n",
- xclk_freq);
- return -EINVAL;
- }
+ ov5645->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
+ if (IS_ERR(ov5645->pwdn_gpio))
+ dev_warn(dev, "Failed to get pwdn-gpios\n");
- ret = clk_set_rate(ov5645->xclk, xclk_freq);
+ ret = ov5645_configure_regulators(ov5645);
if (ret) {
- dev_err(dev, "could not set xclk frequency\n");
- return ret;
- }
-
- ov5645->io_regulator = devm_regulator_get(dev, "vdddo");
- if (IS_ERR(ov5645->io_regulator)) {
- dev_err(dev, "cannot get io regulator\n");
- return PTR_ERR(ov5645->io_regulator);
- }
-
- ret = regulator_set_voltage(ov5645->io_regulator,
- OV5645_VOLTAGE_DIGITAL_IO,
- OV5645_VOLTAGE_DIGITAL_IO);
- if (ret < 0) {
- dev_err(dev, "cannot set io voltage\n");
- return ret;
- }
-
- ov5645->core_regulator = devm_regulator_get(dev, "vddd");
- if (IS_ERR(ov5645->core_regulator)) {
- dev_err(dev, "cannot get core regulator\n");
- return PTR_ERR(ov5645->core_regulator);
- }
-
- ret = regulator_set_voltage(ov5645->core_regulator,
- OV5645_VOLTAGE_DIGITAL_CORE,
- OV5645_VOLTAGE_DIGITAL_CORE);
- if (ret < 0) {
- dev_err(dev, "cannot set core voltage\n");
- return ret;
- }
-
- ov5645->analog_regulator = devm_regulator_get(dev, "vdda");
- if (IS_ERR(ov5645->analog_regulator)) {
- dev_err(dev, "cannot get analog regulator\n");
- return PTR_ERR(ov5645->analog_regulator);
- }
-
- ret = regulator_set_voltage(ov5645->analog_regulator,
- OV5645_VOLTAGE_ANALOG,
- OV5645_VOLTAGE_ANALOG);
- if (ret < 0) {
- dev_err(dev, "cannot set analog voltage\n");
+ dev_err(dev, "Failed to get power regulators\n");
return ret;
}
- ov5645->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
- if (IS_ERR(ov5645->enable_gpio)) {
- dev_err(dev, "cannot get enable gpio\n");
- return PTR_ERR(ov5645->enable_gpio);
+ ov5645->pinctrl = devm_pinctrl_get(dev);
+ if (!IS_ERR(ov5645->pinctrl)) {
+ ov5645->pins_default =
+ pinctrl_lookup_state(ov5645->pinctrl,
+ OF_CAMERA_PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(ov5645->pins_default))
+ dev_err(dev, "could not get default pinstate\n");
+
+ ov5645->pins_sleep =
+ pinctrl_lookup_state(ov5645->pinctrl,
+ OF_CAMERA_PINCTRL_STATE_SLEEP);
+ if (IS_ERR(ov5645->pins_sleep))
+ dev_err(dev, "could not get sleep pinstate\n");
}
- ov5645->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
- if (IS_ERR(ov5645->rst_gpio)) {
- dev_err(dev, "cannot get reset gpio\n");
- return PTR_ERR(ov5645->rst_gpio);
- }
-
- mutex_init(&ov5645->power_lock);
+ mutex_init(&ov5645->mutex);
- v4l2_ctrl_handler_init(&ov5645->ctrls, 9);
- v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops,
+ v4l2_ctrl_handler_init(&ov5645->ctrl_handler, 9);
+ v4l2_ctrl_new_std(&ov5645->ctrl_handler, &ov5645_ctrl_ops,
V4L2_CID_SATURATION, -4, 4, 1, 0);
- v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops,
+ v4l2_ctrl_new_std(&ov5645->ctrl_handler, &ov5645_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops,
+ v4l2_ctrl_new_std(&ov5645->ctrl_handler, &ov5645_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops,
+ v4l2_ctrl_new_std(&ov5645->ctrl_handler, &ov5645_ctrl_ops,
V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
- v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops,
+ v4l2_ctrl_new_std(&ov5645->ctrl_handler, &ov5645_ctrl_ops,
V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
- v4l2_ctrl_new_std_menu(&ov5645->ctrls, &ov5645_ctrl_ops,
+ v4l2_ctrl_new_std_menu(&ov5645->ctrl_handler, &ov5645_ctrl_ops,
V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL,
0, V4L2_EXPOSURE_AUTO);
- v4l2_ctrl_new_std_menu_items(&ov5645->ctrls, &ov5645_ctrl_ops,
+ v4l2_ctrl_new_std_menu_items(&ov5645->ctrl_handler, &ov5645_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(ov5645_test_pattern_menu) - 1,
0, 0, ov5645_test_pattern_menu);
- ov5645->pixel_clock = v4l2_ctrl_new_std(&ov5645->ctrls,
+ ov5645->pixel_clock = v4l2_ctrl_new_std(&ov5645->ctrl_handler,
&ov5645_ctrl_ops,
V4L2_CID_PIXEL_RATE,
1, INT_MAX, 1, 1);
- ov5645->link_freq = v4l2_ctrl_new_int_menu(&ov5645->ctrls,
+ ov5645->link_freq = v4l2_ctrl_new_int_menu(&ov5645->ctrl_handler,
&ov5645_ctrl_ops,
V4L2_CID_LINK_FREQ,
- ARRAY_SIZE(link_freq) - 1,
- 0, link_freq);
+ ARRAY_SIZE(link_freq_menu_items) - 1,
+ 0, link_freq_menu_items);
if (ov5645->link_freq)
ov5645->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
- ov5645->sd.ctrl_handler = &ov5645->ctrls;
+ ov5645->subdev.ctrl_handler = &ov5645->ctrl_handler;
- if (ov5645->ctrls.error) {
+ if (ov5645->ctrl_handler.error) {
dev_err(dev, "%s: control initialization error %d\n",
- __func__, ov5645->ctrls.error);
- ret = ov5645->ctrls.error;
- goto free_ctrl;
- }
-
- v4l2_i2c_subdev_init(&ov5645->sd, client, &ov5645_subdev_ops);
- ov5645->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- ov5645->pad.flags = MEDIA_PAD_FL_SOURCE;
- ov5645->sd.dev = &client->dev;
- ov5645->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-
- ret = media_entity_pads_init(&ov5645->sd.entity, 1, &ov5645->pad);
- if (ret < 0) {
- dev_err(dev, "could not register media entity\n");
- goto free_ctrl;
+ __func__, ov5645->ctrl_handler.error);
+ ret = ov5645->ctrl_handler.error;
+ goto err_free_handler;
}
- ret = ov5645_s_power(&ov5645->sd, true);
- if (ret < 0) {
- dev_err(dev, "could not power up OV5645\n");
- goto free_entity;
- }
+ sd = &ov5645->subdev;
+ v4l2_i2c_subdev_init(sd, client, &ov5645_subdev_ops);
- ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_HIGH, &chip_id_high);
- if (ret < 0 || chip_id_high != OV5645_CHIP_ID_HIGH_BYTE) {
- dev_err(dev, "could not read ID high\n");
- ret = -ENODEV;
- goto power_down;
- }
- ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_LOW, &chip_id_low);
- if (ret < 0 || chip_id_low != OV5645_CHIP_ID_LOW_BYTE) {
- dev_err(dev, "could not read ID low\n");
- ret = -ENODEV;
- goto power_down;
- }
+ ret = __ov5645_power_on(ov5645);
+ if (ret)
+ goto err_free_handler;
- dev_info(dev, "OV5645 detected at address 0x%02x\n", client->addr);
+ ret = ov5645_check_sensor_id(ov5645, client);
+ if (ret)
+ goto err_power_off;
- ret = ov5645_read_reg(ov5645, OV5645_AEC_PK_MANUAL,
- &ov5645->aec_pk_manual);
+ ret = ov5645_read_reg(client, OV5645_AEC_PK_MANUAL,
+ OV5645_REG_VALUE_08BIT,&ov5645->aec_pk_manual);
if (ret < 0) {
dev_err(dev, "could not read AEC/AGC mode\n");
ret = -ENODEV;
- goto power_down;
+ goto err_power_off;
}
- ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG20,
- &ov5645->timing_tc_reg20);
+ ret = ov5645_read_reg(client, OV5645_TIMING_TC_REG20,
+ OV5645_REG_VALUE_08BIT,&ov5645->timing_tc_reg20);
if (ret < 0) {
dev_err(dev, "could not read vflip value\n");
ret = -ENODEV;
- goto power_down;
+ goto err_power_off;
}
- ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG21,
- &ov5645->timing_tc_reg21);
+ ret = ov5645_read_reg(client, OV5645_TIMING_TC_REG21,
+ OV5645_REG_VALUE_08BIT,&ov5645->timing_tc_reg21);
if (ret < 0) {
dev_err(dev, "could not read hflip value\n");
ret = -ENODEV;
- goto power_down;
+ goto err_power_off;
}
- ov5645_s_power(&ov5645->sd, false);
+ sd->internal_ops = &ov5645_internal_ops;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ ov5645->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &ov5645->pad);
+ if (ret < 0)
+ goto err_power_off;
- ret = v4l2_async_register_subdev(&ov5645->sd);
- if (ret < 0) {
- dev_err(dev, "could not register v4l2 device\n");
- goto free_entity;
+ ret = v4l2_async_register_subdev(sd);
+ if (ret) {
+ dev_err(dev, "v4l2 async register subdev failed\n");
+ goto err_clean_entity;
}
- ov5645_entity_init_cfg(&ov5645->sd, NULL);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
return 0;
-power_down:
- ov5645_s_power(&ov5645->sd, false);
-free_entity:
- media_entity_cleanup(&ov5645->sd.entity);
-free_ctrl:
- v4l2_ctrl_handler_free(&ov5645->ctrls);
- mutex_destroy(&ov5645->power_lock);
+err_clean_entity:
+ media_entity_cleanup(&sd->entity);
+err_power_off:
+ __ov5645_power_off(ov5645);
+err_free_handler:
+ v4l2_ctrl_handler_free(&ov5645->ctrl_handler);
+
+ mutex_destroy(&ov5645->mutex);
return ret;
}
@@ -1338,38 +1366,55 @@ static int ov5645_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct ov5645 *ov5645 = to_ov5645(sd);
- v4l2_async_unregister_subdev(&ov5645->sd);
- media_entity_cleanup(&ov5645->sd.entity);
- v4l2_ctrl_handler_free(&ov5645->ctrls);
- mutex_destroy(&ov5645->power_lock);
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(&ov5645->ctrl_handler);
+ mutex_destroy(&ov5645->mutex);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ __ov5645_power_off(ov5645);
+ pm_runtime_set_suspended(&client->dev);
return 0;
}
-static const struct i2c_device_id ov5645_id[] = {
- { "ov5645", 0 },
- {}
-};
-MODULE_DEVICE_TABLE(i2c, ov5645_id);
-
+#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id ov5645_of_match[] = {
{ .compatible = "ovti,ov5645" },
- { /* sentinel */ }
+ {},
};
MODULE_DEVICE_TABLE(of, ov5645_of_match);
+#endif
+
+static const struct i2c_device_id ov5645_match_id[] = {
+ { "ovti,ov5645", 0 },
+ { },
+};
static struct i2c_driver ov5645_i2c_driver = {
.driver = {
+ .name = "ov5645",
+ .pm = &ov5645_pm_ops,
.of_match_table = of_match_ptr(ov5645_of_match),
- .name = "ov5645",
},
- .probe = ov5645_probe,
- .remove = ov5645_remove,
- .id_table = ov5645_id,
+ .probe = &ov5645_probe,
+ .remove = &ov5645_remove,
+ .id_table = ov5645_match_id,
};
-module_i2c_driver(ov5645_i2c_driver);
+static int __init sensor_mod_init(void)
+{
+ return i2c_add_driver(&ov5645_i2c_driver);
+}
+
+static void __exit sensor_mod_exit(void)
+{
+ i2c_del_driver(&ov5645_i2c_driver);
+}
+
+device_initcall_sync(sensor_mod_init);
+module_exit(sensor_mod_exit);
-MODULE_DESCRIPTION("Omnivision OV5645 Camera Driver");
-MODULE_AUTHOR("Todor Tomov <todor.tomov@linaro.org>");
+MODULE_DESCRIPTION("OmniVision ov5645 sensor driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c b/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c
index 100c2e397560..e1d4db68b51e 100644
--- a/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c
+++ b/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Rockchip MIPI Synopsys DPHY driver
*
@@ -325,7 +325,12 @@ static int mipidphy_get_sensor_data_rate(struct v4l2_subdev *sd)
static int mipidphy_s_stream_start(struct v4l2_subdev *sd)
{
struct mipidphy_priv *priv = to_dphy_priv(sd);
- int ret = 0;
+ struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
+ struct mipidphy_sensor *sensor = sd_to_sensor(priv, sensor_sd);
+ const struct dphy_drv_data *drv_data = priv->drv_data;
+ const struct hsfreq_range *hsfreq_ranges = drv_data->hsfreq_ranges;
+ int num_hsfreq_ranges = drv_data->num_hsfreq_ranges;
+ int i, ret, hsfreq = 0;
if (priv->is_streaming)
return 0;
@@ -334,7 +339,40 @@ static int mipidphy_s_stream_start(struct v4l2_subdev *sd)
if (ret < 0)
return ret;
- priv->stream_on(priv, sd);
+ for (i = 0; i < num_hsfreq_ranges; i++) {
+ if (hsfreq_ranges[i].range_h >= priv->data_rate_mbps) {
+ hsfreq = hsfreq_ranges[i].cfg_bit;
+ break;
+ }
+ }
+
+ write_grf_reg(priv, GRF_DPHY_RX0_FORCERXMODE, 0);
+ write_grf_reg(priv, GRF_DPHY_RX0_FORCETXSTOPMODE, 0);
+ /* Disable lan turn around, which is ignored in receive mode */
+ write_grf_reg(priv, GRF_DPHY_RX0_TURNREQUEST, 0);
+ write_grf_reg(priv, GRF_DPHY_RX0_TURNDISABLE, 0xf);
+ write_grf_reg(priv, GRF_DPHY_RX0_ENABLE, GENMASK(sensor->lanes - 1, 0));
+ /* dphy start */
+ write_grf_reg(priv, GRF_DPHY_RX0_TESTCLK, 1);
+ write_grf_reg(priv, GRF_DPHY_RX0_TESTCLR, 1);
+ usleep_range(100, 150);
+ write_grf_reg(priv, GRF_DPHY_RX0_TESTCLR, 0);
+ usleep_range(100, 150);
+ /* set clock lane */
+ /* HS hsfreq_range & lane 0 settle bypass */
+ mipidphy0_wr_reg(priv, CLOCK_LANE_HS_RX_CONTROL, 0);
+ /* HS RX Control of lane0 */
+ mipidphy0_wr_reg(priv, LANE0_HS_RX_CONTROL, hsfreq << 1);
+ /* HS RX Control of lane1 */
+ mipidphy0_wr_reg(priv, LANE1_HS_RX_CONTROL, 0);
+ /* HS RX Control of lane2 */
+ mipidphy0_wr_reg(priv, LANE2_HS_RX_CONTROL, 0);
+ /* HS RX Control of lane3 */
+ mipidphy0_wr_reg(priv, LANE3_HS_RX_CONTROL, 0);
+ /* HS RX Data Lanes Settle State Time Control */
+ mipidphy0_wr_reg(priv, HS_RX_DATA_LANES_THS_SETTLE_CONTROL, 0x04);
+ /* Normal operation */
+ mipidphy0_wr_reg(priv, 0x0, 0);
priv->is_streaming = true;
@@ -809,12 +847,6 @@ static int rockchip_mipidphy_probe(struct platform_device *pdev)
priv->grf_regs = drv_data->regs;
priv->drv_data = drv_data;
- priv->stream_on = mipidphy_txrx_stream_on;
- priv->txrx_base_addr = NULL;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->txrx_base_addr = devm_ioremap_resource(dev, res);
- if (IS_ERR(priv->txrx_base_addr))
- priv->stream_on = mipidphy_rx_stream_on;
sd = &priv->sd;
v4l2_subdev_init(sd, &mipidphy_subdev_ops);