Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:ateixeira:xps13
intel-ipu6
0026-ov08x40-add-handshake-pin-support.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0026-ov08x40-add-handshake-pin-support.patch of Package intel-ipu6
From: Serin Yeh <serin.yeh@intel.com> Date: Tue, 19 Mar 2024 17:43:56 +0800 Subject: ov08x40: add handshake pin support BugLink: https://bugs.launchpad.net/bugs/2060101 Signed-off-by: You-Sheng Yang <vicamo.yang@canonical.com> --- drivers/media/i2c/ov08x40.c | 114 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 7 deletions(-) diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c index 48df077..14bb46b 100644 --- a/drivers/media/i2c/ov08x40.c +++ b/drivers/media/i2c/ov08x40.c @@ -6,6 +6,7 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/delay.h> +#include <linux/clk.h> #include <linux/pm_runtime.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -1291,6 +1292,15 @@ struct ov08x40 { struct v4l2_ctrl *hblank; struct v4l2_ctrl *exposure; + /* GPIO for reset */ + struct gpio_desc *reset; + /* GPIO for Lattice handshake */ + struct gpio_desc *handshake; + /* regulator */ + struct regulator *avdd; + /* Clock provider */ + struct clk *img_clk; + /* Current mode */ const struct ov08x40_mode *cur_mode; @@ -1883,6 +1893,51 @@ err_unlock: return ret; } +static int ov08x40_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov08x40 *ov08x40 = to_ov08x40(sd); + int ret = 0; + + gpiod_set_value_cansleep(ov08x40->reset, 1); + gpiod_set_value_cansleep(ov08x40->handshake, 0); + if (ov08x40->avdd) + ret = regulator_disable(ov08x40->avdd); + clk_disable_unprepare(ov08x40->img_clk); + + return ret; +} + +static int ov08x40_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov08x40 *ov08x40 = to_ov08x40(sd); + int ret; + + ret = clk_prepare_enable(ov08x40->img_clk); + if (ret < 0) { + dev_err(dev, "failed to enable imaging clock: %d", ret); + return ret; + } + if (ov08x40->avdd) { + ret = regulator_enable(ov08x40->avdd); + if (ret < 0) { + dev_err(dev, "failed to enable avdd: %d", ret); + clk_disable_unprepare(ov08x40->img_clk); + return ret; + } + } + gpiod_set_value_cansleep(ov08x40->handshake, 1); + gpiod_set_value_cansleep(ov08x40->reset, 0); + + /* Lattice MIPI aggregator with some version FW needs longer delay + after handshake triggered. We set 25ms as a safe value and wait + for a stable version FW. */ + msleep_interruptible(25); + + return ret; +} + /* Verify chip ID */ static int ov08x40_identify_module(struct ov08x40 *ov08x) { @@ -2049,6 +2104,41 @@ static void ov08x40_free_controls(struct ov08x40 *ov08x) mutex_destroy(&ov08x->mutex); } + +static int ov08x40_get_pm_resources(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov08x40 *ov08x40 = to_ov08x40(sd); + int ret; + + ov08x40->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ov08x40->reset)) + return dev_err_probe(dev, PTR_ERR(ov08x40->reset), + "failed to get reset gpio\n"); + + ov08x40->handshake = devm_gpiod_get_optional(dev, "handshake", + GPIOD_OUT_LOW); + if (IS_ERR(ov08x40->handshake)) + return dev_err_probe(dev, PTR_ERR(ov08x40->handshake), + "failed to get handshake gpio\n"); + + ov08x40->img_clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(ov08x40->img_clk)) + return dev_err_probe(dev, PTR_ERR(ov08x40->img_clk), + "failed to get imaging clock\n"); + + ov08x40->avdd = devm_regulator_get_optional(dev, "avdd"); + if (IS_ERR(ov08x40->avdd)) { + ret = PTR_ERR(ov08x40->avdd); + ov08x40->avdd = NULL; + if (ret != -ENODEV) + return dev_err_probe(dev, ret, + "failed to get avdd regulator\n"); + } + + return 0; +} + static int ov08x40_check_hwcfg(struct device *dev) { struct v4l2_fwnode_endpoint bus_cfg = { @@ -2060,8 +2150,10 @@ static int ov08x40_check_hwcfg(struct device *dev) int ret; u32 ext_clk; - if (!fwnode) - return -ENXIO; + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + dev_dbg(dev, "fwnode_graph_get_next_endpoint = %d\n", ep); + if (!ep) + return -EPROBE_DEFER; ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", &ext_clk); @@ -2076,10 +2168,6 @@ static int ov08x40_check_hwcfg(struct device *dev) return -EINVAL; } - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); - if (!ep) - return -ENXIO; - ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); fwnode_handle_put(ep); if (ret) @@ -2141,6 +2229,17 @@ static int ov08x40_probe(struct i2c_client *client) full_power = acpi_dev_state_d0(&client->dev); if (full_power) { + dev_err(&client->dev, "start full_power\n"); + ret = ov08x40_get_pm_resources(&client->dev); + if (ret) + return ret; + ret = ov08x40_power_on(&client->dev); + if (ret) { + dev_err_probe(&client->dev, ret, + "failed to power on\n"); + goto probe_error_ret; + } + /* Check module identity */ ret = ov08x40_identify_module(ov08x); if (ret) { @@ -2187,6 +2286,8 @@ error_media_entity: error_handler_free: ov08x40_free_controls(ov08x); +probe_error_ret: + ov08x40_power_off(&client->dev); return ret; } @@ -2219,7 +2320,6 @@ static struct i2c_driver ov08x40_i2c_driver = { }, .probe = ov08x40_probe, .remove = ov08x40_remove, - .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, }; module_i2c_driver(ov08x40_i2c_driver);
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor