390 lines
12 KiB
Diff
390 lines
12 KiB
Diff
From 77077ade56f3fc0a00fa2a9332f305d06c1d0f1f Mon Sep 17 00:00:00 2001
|
|
From: Ondrej Jirman <megi@xff.cz>
|
|
Date: Sun, 22 May 2022 14:31:08 +0200
|
|
Subject: [PATCH 333/391] media: i2c: ov8858: Port BSP driver to 5.18 and
|
|
improve DT bindings
|
|
|
|
- drop power-gpios
|
|
- use optional gpio instead of error checks everywhere
|
|
- assume positive meaning for gpios with inversion handled in DT
|
|
- don't touch default pinctrl setup
|
|
- simplify powerup
|
|
|
|
Signed-off-by: Ondrej Jirman <megi@xff.cz>
|
|
---
|
|
drivers/media/i2c/ov8858.c | 132 ++++++++++++++-----------------------
|
|
1 file changed, 50 insertions(+), 82 deletions(-)
|
|
|
|
diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c
|
|
index 11f01e30b..69ec1efef 100644
|
|
--- a/drivers/media/i2c/ov8858.c
|
|
+++ b/drivers/media/i2c/ov8858.c
|
|
@@ -21,7 +21,7 @@
|
|
#include <linux/slab.h>
|
|
#include <linux/pinctrl/consumer.h>
|
|
#include <linux/version.h>
|
|
-#include <linux/rk-camera-module.h>
|
|
+#include "rk-camera-module.h"
|
|
|
|
#include <media/v4l2-async.h>
|
|
#include <media/media-entity.h>
|
|
@@ -34,8 +34,6 @@
|
|
#include <media/v4l2-mediabus.h>
|
|
#include <media/v4l2-subdev.h>
|
|
|
|
-#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x03)
|
|
-
|
|
#ifndef V4L2_CID_DIGITAL_GAIN
|
|
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
|
|
#endif
|
|
@@ -158,7 +156,6 @@ struct ov8858_mode {
|
|
struct ov8858 {
|
|
struct i2c_client *client;
|
|
struct clk *xvclk;
|
|
- struct gpio_desc *power_gpio;
|
|
struct gpio_desc *reset_gpio;
|
|
struct gpio_desc *pwdn_gpio;
|
|
struct regulator_bulk_data supplies[OV8858_NUM_SUPPLIES];
|
|
@@ -1488,7 +1485,7 @@ ov8858_find_best_fit(struct ov8858 *ov8858,
|
|
}
|
|
|
|
static int ov8858_set_fmt(struct v4l2_subdev *sd,
|
|
- struct v4l2_subdev_pad_config *cfg,
|
|
+ struct v4l2_subdev_state *state,
|
|
struct v4l2_subdev_format *fmt)
|
|
{
|
|
struct ov8858 *ov8858 = to_ov8858(sd);
|
|
@@ -1504,7 +1501,7 @@ static int ov8858_set_fmt(struct v4l2_subdev *sd,
|
|
fmt->format.field = V4L2_FIELD_NONE;
|
|
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
|
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
|
- *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
|
|
+ *v4l2_subdev_get_try_format(sd, state, fmt->pad) = fmt->format;
|
|
#else
|
|
mutex_unlock(&ov8858->mutex);
|
|
return -ENOTTY;
|
|
@@ -1526,7 +1523,7 @@ static int ov8858_set_fmt(struct v4l2_subdev *sd,
|
|
}
|
|
|
|
static int ov8858_get_fmt(struct v4l2_subdev *sd,
|
|
- struct v4l2_subdev_pad_config *cfg,
|
|
+ struct v4l2_subdev_state *state,
|
|
struct v4l2_subdev_format *fmt)
|
|
{
|
|
struct ov8858 *ov8858 = to_ov8858(sd);
|
|
@@ -1535,7 +1532,7 @@ static int ov8858_get_fmt(struct v4l2_subdev *sd,
|
|
mutex_lock(&ov8858->mutex);
|
|
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
|
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
|
- fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
|
|
+ fmt->format = *v4l2_subdev_get_try_format(sd, state, fmt->pad);
|
|
#else
|
|
mutex_unlock(&ov8858->mutex);
|
|
return -ENOTTY;
|
|
@@ -1552,7 +1549,7 @@ static int ov8858_get_fmt(struct v4l2_subdev *sd,
|
|
}
|
|
|
|
static int ov8858_enum_mbus_code(struct v4l2_subdev *sd,
|
|
- struct v4l2_subdev_pad_config *cfg,
|
|
+ struct v4l2_subdev_state *state,
|
|
struct v4l2_subdev_mbus_code_enum *code)
|
|
{
|
|
if (code->index != 0)
|
|
@@ -1563,7 +1560,7 @@ static int ov8858_enum_mbus_code(struct v4l2_subdev *sd,
|
|
}
|
|
|
|
static int ov8858_enum_frame_sizes(struct v4l2_subdev *sd,
|
|
- struct v4l2_subdev_pad_config *cfg,
|
|
+ struct v4l2_subdev_state *state,
|
|
struct v4l2_subdev_frame_size_enum *fse)
|
|
{
|
|
struct ov8858 *ov8858 = to_ov8858(sd);
|
|
@@ -2137,11 +2134,6 @@ static int __ov8858_power_on(struct ov8858 *ov8858)
|
|
u32 delay_us;
|
|
struct device *dev = &ov8858->client->dev;
|
|
|
|
- if (!IS_ERR(ov8858->power_gpio))
|
|
- gpiod_set_value_cansleep(ov8858->power_gpio, 1);
|
|
-
|
|
- usleep_range(1000, 2000);
|
|
-
|
|
if (!IS_ERR_OR_NULL(ov8858->pins_default)) {
|
|
ret = pinctrl_select_state(ov8858->pinctrl,
|
|
ov8858->pins_default);
|
|
@@ -2154,31 +2146,28 @@ static int __ov8858_power_on(struct ov8858 *ov8858)
|
|
dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
|
|
if (clk_get_rate(ov8858->xvclk) != OV8858_XVCLK_FREQ)
|
|
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
|
|
+
|
|
ret = clk_prepare_enable(ov8858->xvclk);
|
|
if (ret < 0) {
|
|
dev_err(dev, "Failed to enable xvclk\n");
|
|
return ret;
|
|
}
|
|
|
|
- if (!IS_ERR(ov8858->reset_gpio))
|
|
- gpiod_set_value_cansleep(ov8858->reset_gpio, 0);
|
|
-
|
|
ret = regulator_bulk_enable(OV8858_NUM_SUPPLIES, ov8858->supplies);
|
|
if (ret < 0) {
|
|
dev_err(dev, "Failed to enable regulators\n");
|
|
goto disable_clk;
|
|
}
|
|
|
|
- if (!IS_ERR(ov8858->reset_gpio))
|
|
- gpiod_set_value_cansleep(ov8858->reset_gpio, 1);
|
|
+ mdelay(20);
|
|
|
|
- usleep_range(1000, 2000);
|
|
- if (!IS_ERR(ov8858->pwdn_gpio))
|
|
- gpiod_set_value_cansleep(ov8858->pwdn_gpio, 1);
|
|
+ gpiod_set_value_cansleep(ov8858->reset_gpio, 0);
|
|
+ gpiod_set_value_cansleep(ov8858->pwdn_gpio, 0);
|
|
|
|
/* 8192 cycles prior to first SCCB transaction */
|
|
- delay_us = ov8858_cal_delay(8192);
|
|
- usleep_range(delay_us, delay_us * 2);
|
|
+ //delay_us = ov8858_cal_delay(8192);
|
|
+ //usleep_range(delay_us, delay_us * 2);
|
|
+ mdelay(10);
|
|
|
|
return 0;
|
|
|
|
@@ -2193,11 +2182,10 @@ static void __ov8858_power_off(struct ov8858 *ov8858)
|
|
int ret;
|
|
struct device *dev = &ov8858->client->dev;
|
|
|
|
- if (!IS_ERR(ov8858->pwdn_gpio))
|
|
- gpiod_set_value_cansleep(ov8858->pwdn_gpio, 0);
|
|
+ gpiod_set_value_cansleep(ov8858->pwdn_gpio, 1);
|
|
clk_disable_unprepare(ov8858->xvclk);
|
|
- if (!IS_ERR(ov8858->reset_gpio))
|
|
- gpiod_set_value_cansleep(ov8858->reset_gpio, 0);
|
|
+ gpiod_set_value_cansleep(ov8858->reset_gpio, 1);
|
|
+
|
|
if (!IS_ERR_OR_NULL(ov8858->pins_sleep)) {
|
|
ret = pinctrl_select_state(ov8858->pinctrl,
|
|
ov8858->pins_sleep);
|
|
@@ -2205,9 +2193,6 @@ static void __ov8858_power_off(struct ov8858 *ov8858)
|
|
dev_dbg(dev, "could not set pins\n");
|
|
}
|
|
|
|
- //if (!IS_ERR(ov8858->power_gpio))
|
|
- //gpiod_set_value_cansleep(ov8858->power_gpio, 0);
|
|
-
|
|
regulator_bulk_disable(OV8858_NUM_SUPPLIES, ov8858->supplies);
|
|
}
|
|
|
|
@@ -2236,7 +2221,7 @@ static int ov8858_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
|
{
|
|
struct ov8858 *ov8858 = to_ov8858(sd);
|
|
struct v4l2_mbus_framefmt *try_fmt =
|
|
- v4l2_subdev_get_try_format(sd, fh->pad, 0);
|
|
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
|
|
const struct ov8858_mode *def_mode = &supported_modes[0];
|
|
|
|
mutex_lock(&ov8858->mutex);
|
|
@@ -2254,7 +2239,7 @@ static int ov8858_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
|
#endif
|
|
|
|
static int ov8858_enum_frame_interval(struct v4l2_subdev *sd,
|
|
- struct v4l2_subdev_pad_config *cfg,
|
|
+ struct v4l2_subdev_state *state,
|
|
struct v4l2_subdev_frame_interval_enum *fie)
|
|
{
|
|
struct ov8858 *ov8858 = to_ov8858(sd);
|
|
@@ -2726,18 +2711,19 @@ static int ov8858_check_sensor_id(struct ov8858 *ov8858,
|
|
int ret;
|
|
|
|
ret = ov8858_read_reg(client, OV8858_REG_CHIP_ID,
|
|
- OV8858_REG_VALUE_24BIT, &id);
|
|
+ OV8858_REG_VALUE_24BIT, &id);
|
|
if (id != CHIP_ID) {
|
|
dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = ov8858_read_reg(client, OV8858_CHIP_REVISION_REG,
|
|
- OV8858_REG_VALUE_08BIT, &id);
|
|
+ OV8858_REG_VALUE_08BIT, &id);
|
|
if (ret) {
|
|
dev_err(dev, "Read chip revision register error\n");
|
|
return ret;
|
|
}
|
|
+
|
|
dev_info(dev, "Detected OV%06x sensor, REVISION 0x%x\n", CHIP_ID, id);
|
|
|
|
if (id == OV8858_R2A) {
|
|
@@ -2781,6 +2767,7 @@ static int ov8858_parse_of(struct ov8858 *ov8858)
|
|
dev_err(dev, "Failed to get endpoint\n");
|
|
return -EINVAL;
|
|
}
|
|
+
|
|
fwnode = of_fwnode_handle(endpoint);
|
|
rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0);
|
|
if (rval <= 0) {
|
|
@@ -2821,16 +2808,12 @@ static int ov8858_probe(struct i2c_client *client,
|
|
char facing[2];
|
|
int ret;
|
|
|
|
- dev_info(dev, "driver version: %02x.%02x.%02x",
|
|
- DRIVER_VERSION >> 16,
|
|
- (DRIVER_VERSION & 0xff00) >> 8,
|
|
- DRIVER_VERSION & 0x00ff);
|
|
-
|
|
ov8858 = devm_kzalloc(dev, sizeof(*ov8858), GFP_KERNEL);
|
|
if (!ov8858)
|
|
return -ENOMEM;
|
|
|
|
ov8858->client = client;
|
|
+
|
|
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
|
|
&ov8858->module_index);
|
|
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
|
|
@@ -2839,40 +2822,37 @@ static int ov8858_probe(struct i2c_client *client,
|
|
&ov8858->module_name);
|
|
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
|
|
&ov8858->len_name);
|
|
- if (ret) {
|
|
- dev_err(dev,
|
|
+ if (ret)
|
|
+ return dev_err_probe(dev, -EINVAL,
|
|
"could not get module information!\n");
|
|
- return -EINVAL;
|
|
- }
|
|
|
|
ov8858->xvclk = devm_clk_get(dev, "xvclk");
|
|
- if (IS_ERR(ov8858->xvclk)) {
|
|
- dev_err(dev, "Failed to get xvclk\n");
|
|
- return -EINVAL;
|
|
- }
|
|
+ if (IS_ERR(ov8858->xvclk))
|
|
+ return dev_err_probe(dev, PTR_ERR(ov8858->xvclk),
|
|
+ "Failed to get xvclk\n");
|
|
|
|
- ov8858->power_gpio = devm_gpiod_get(dev, "power", GPIOD_OUT_LOW);
|
|
- if (IS_ERR(ov8858->power_gpio))
|
|
- dev_warn(dev, "Failed to get power-gpios, maybe no use\n");
|
|
-
|
|
- ov8858->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
|
+ ov8858->reset_gpio = devm_gpiod_get_optional(dev, "reset",
|
|
+ GPIOD_OUT_HIGH);
|
|
if (IS_ERR(ov8858->reset_gpio))
|
|
- dev_warn(dev, "Failed to get reset-gpios, maybe no use\n");
|
|
+ return dev_err_probe(dev, PTR_ERR(ov8858->reset_gpio),
|
|
+ "Failed to get reset gpio\n");
|
|
|
|
- ov8858->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
|
|
+ ov8858->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
|
|
+ GPIOD_OUT_HIGH);
|
|
if (IS_ERR(ov8858->pwdn_gpio))
|
|
- dev_warn(dev, "Failed to get pwdn-gpios, maybe no use\n");
|
|
+ return dev_err_probe(dev, PTR_ERR(ov8858->pwdn_gpio),
|
|
+ "Failed to get powerdown gpio\n");
|
|
|
|
ret = ov8858_configure_regulators(ov8858);
|
|
- if (ret) {
|
|
- dev_err(dev, "Failed to get power regulators\n");
|
|
- return ret;
|
|
- }
|
|
+ if (ret)
|
|
+ return dev_err_probe(dev, ret,
|
|
+ "Failed to get power regulators\n");
|
|
|
|
ret = ov8858_parse_of(ov8858);
|
|
if (ret != 0)
|
|
return -EINVAL;
|
|
|
|
+ /*
|
|
ov8858->pinctrl = devm_pinctrl_get(dev);
|
|
if (!IS_ERR(ov8858->pinctrl)) {
|
|
ov8858->pins_default =
|
|
@@ -2887,6 +2867,7 @@ static int ov8858_probe(struct i2c_client *client,
|
|
if (IS_ERR(ov8858->pins_sleep))
|
|
dev_err(dev, "could not get sleep pinstate\n");
|
|
}
|
|
+ */
|
|
|
|
mutex_init(&ov8858->mutex);
|
|
|
|
@@ -2910,10 +2891,10 @@ static int ov8858_probe(struct i2c_client *client,
|
|
sd->internal_ops = &ov8858_internal_ops;
|
|
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
|
#endif
|
|
-#if defined(CONFIG_MEDIA_CONTROLLER)
|
|
+#ifdef CONFIG_MEDIA_CONTROLLER
|
|
ov8858->pad.flags = MEDIA_PAD_FL_SOURCE;
|
|
- sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
|
|
- ret = media_entity_init(&sd->entity, 1, &ov8858->pad, 0);
|
|
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
|
|
+ ret = media_entity_pads_init(&sd->entity, 1, &ov8858->pad);
|
|
if (ret < 0)
|
|
goto err_power_off;
|
|
#endif
|
|
@@ -2927,7 +2908,7 @@ static int ov8858_probe(struct i2c_client *client,
|
|
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
|
|
ov8858->module_index, facing,
|
|
OV8858_NAME, dev_name(sd->dev));
|
|
- ret = v4l2_async_register_subdev_sensor_common(sd);
|
|
+ ret = v4l2_async_register_subdev_sensor(sd);
|
|
if (ret) {
|
|
dev_err(dev, "v4l2 async register subdev failed\n");
|
|
goto err_clean_entity;
|
|
@@ -2940,7 +2921,7 @@ static int ov8858_probe(struct i2c_client *client,
|
|
return 0;
|
|
|
|
err_clean_entity:
|
|
-#if defined(CONFIG_MEDIA_CONTROLLER)
|
|
+#ifdef CONFIG_MEDIA_CONTROLLER
|
|
media_entity_cleanup(&sd->entity);
|
|
#endif
|
|
err_power_off:
|
|
@@ -2953,13 +2934,13 @@ static int ov8858_probe(struct i2c_client *client,
|
|
return ret;
|
|
}
|
|
|
|
-static int ov8858_remove(struct i2c_client *client)
|
|
+static void ov8858_remove(struct i2c_client *client)
|
|
{
|
|
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
|
struct ov8858 *ov8858 = to_ov8858(sd);
|
|
|
|
v4l2_async_unregister_subdev(sd);
|
|
-#if defined(CONFIG_MEDIA_CONTROLLER)
|
|
+#ifdef CONFIG_MEDIA_CONTROLLER
|
|
media_entity_cleanup(&sd->entity);
|
|
#endif
|
|
v4l2_ctrl_handler_free(&ov8858->ctrl_handler);
|
|
@@ -2973,8 +2954,6 @@ static int ov8858_remove(struct i2c_client *client)
|
|
if (!pm_runtime_status_suspended(&client->dev))
|
|
__ov8858_power_off(ov8858);
|
|
pm_runtime_set_suspended(&client->dev);
|
|
-
|
|
- return 0;
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_OF)
|
|
@@ -3001,18 +2980,7 @@ static struct i2c_driver ov8858_i2c_driver = {
|
|
.id_table = ov8858_match_id,
|
|
};
|
|
|
|
-static int __init sensor_mod_init(void)
|
|
-{
|
|
- return i2c_add_driver(&ov8858_i2c_driver);
|
|
-}
|
|
-
|
|
-static void __exit sensor_mod_exit(void)
|
|
-{
|
|
- i2c_del_driver(&ov8858_i2c_driver);
|
|
-}
|
|
-
|
|
-device_initcall_sync(sensor_mod_init);
|
|
-module_exit(sensor_mod_exit);
|
|
+module_i2c_driver(ov8858_i2c_driver);
|
|
|
|
MODULE_DESCRIPTION("OmniVision ov8858 sensor driver");
|
|
MODULE_LICENSE("GPL v2");
|
|
--
|
|
2.35.3
|
|
|