diff options
Diffstat (limited to 'drivers/media/i2c/og01a1b.c')
-rw-r--r-- | drivers/media/i2c/og01a1b.c | 115 |
1 files changed, 50 insertions, 65 deletions
diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c index 78d5d406e4b7..c7184de6251a 100644 --- a/drivers/media/i2c/og01a1b.c +++ b/drivers/media/i2c/og01a1b.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2022 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> @@ -10,6 +9,8 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -421,6 +422,7 @@ static const struct og01a1b_mode supported_modes[] = { }; struct og01a1b { + struct device *dev; struct clk *xvclk; struct gpio_desc *reset_gpio; struct regulator *avdd; @@ -512,7 +514,6 @@ static int og01a1b_write_reg(struct og01a1b *og01a1b, u16 reg, u16 len, u32 val) static int og01a1b_write_reg_list(struct og01a1b *og01a1b, const struct og01a1b_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); unsigned int i; int ret; @@ -520,7 +521,7 @@ static int og01a1b_write_reg_list(struct og01a1b *og01a1b, ret = og01a1b_write_reg(og01a1b, r_list->regs[i].address, 1, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(og01a1b->dev, "failed to write reg 0x%4.4x. error = %d", r_list->regs[i].address, ret); return ret; @@ -544,7 +545,6 @@ static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) { struct og01a1b *og01a1b = container_of(ctrl->handler, struct og01a1b, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); s64 exposure_max; int ret = 0; @@ -560,7 +560,7 @@ static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(og01a1b->dev)) return 0; switch (ctrl->id) { @@ -596,7 +596,7 @@ static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(og01a1b->dev); return ret; } @@ -682,13 +682,12 @@ static void og01a1b_update_pad_format(const struct og01a1b_mode *mode, { fmt->width = mode->width; fmt->height = mode->height; - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + fmt->code = MEDIA_BUS_FMT_Y10_1X10; fmt->field = V4L2_FIELD_NONE; } static int og01a1b_start_streaming(struct og01a1b *og01a1b) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); const struct og01a1b_reg_list *reg_list; int link_freq_index, ret; @@ -697,14 +696,14 @@ static int og01a1b_start_streaming(struct og01a1b *og01a1b) ret = og01a1b_write_reg_list(og01a1b, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(og01a1b->dev, "failed to set plls"); return ret; } reg_list = &og01a1b->cur_mode->reg_list; ret = og01a1b_write_reg_list(og01a1b, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(og01a1b->dev, "failed to set mode"); return ret; } @@ -716,7 +715,7 @@ static int og01a1b_start_streaming(struct og01a1b *og01a1b) OG01A1B_REG_VALUE_08BIT, OG01A1B_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "failed to set stream"); + dev_err(og01a1b->dev, "failed to set stream"); return ret; } @@ -725,22 +724,19 @@ static int og01a1b_start_streaming(struct og01a1b *og01a1b) static void og01a1b_stop_streaming(struct og01a1b *og01a1b) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); - if (og01a1b_write_reg(og01a1b, OG01A1B_REG_MODE_SELECT, OG01A1B_REG_VALUE_08BIT, OG01A1B_MODE_STANDBY)) - dev_err(&client->dev, "failed to set stream"); + dev_err(og01a1b->dev, "failed to set stream"); } static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) { struct og01a1b *og01a1b = to_og01a1b(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&og01a1b->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(og01a1b->dev); if (ret) { mutex_unlock(&og01a1b->mutex); return ret; @@ -750,11 +746,11 @@ static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; og01a1b_stop_streaming(og01a1b); - pm_runtime_put(&client->dev); + pm_runtime_put(og01a1b->dev); } } else { og01a1b_stop_streaming(og01a1b); - pm_runtime_put(&client->dev); + pm_runtime_put(og01a1b->dev); } mutex_unlock(&og01a1b->mutex); @@ -828,7 +824,7 @@ static int og01a1b_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + code->code = MEDIA_BUS_FMT_Y10_1X10; return 0; } @@ -840,7 +836,7 @@ static int og01a1b_enum_frame_size(struct v4l2_subdev *sd, if (fse->index >= ARRAY_SIZE(supported_modes)) return -EINVAL; - if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + if (fse->code != MEDIA_BUS_FMT_Y10_1X10) return -EINVAL; fse->min_width = supported_modes[fse->index].width; @@ -889,7 +885,6 @@ static const struct v4l2_subdev_internal_ops og01a1b_internal_ops = { static int og01a1b_identify_module(struct og01a1b *og01a1b) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); int ret; u32 val; @@ -899,7 +894,7 @@ static int og01a1b_identify_module(struct og01a1b *og01a1b) return ret; if (val != OG01A1B_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(og01a1b->dev, "chip id mismatch: %x!=%x", OG01A1B_CHIP_ID, val); return -ENXIO; } @@ -909,35 +904,18 @@ static int og01a1b_identify_module(struct og01a1b *og01a1b) static int og01a1b_check_hwcfg(struct og01a1b *og01a1b) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); - struct device *dev = &client->dev; + struct device *dev = og01a1b->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; int ret; unsigned int i, j; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) { - if (!og01a1b->xvclk) { - dev_err(dev, "can't get clock frequency"); - return ret; - } - - mclk = clk_get_rate(og01a1b->xvclk); - } - - if (mclk != OG01A1B_MCLK) { - dev_err(dev, "external clock %d is not supported", mclk); - return -EINVAL; - } - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -1066,47 +1044,54 @@ static void og01a1b_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(og01a1b->dev); mutex_destroy(&og01a1b->mutex); } static int og01a1b_probe(struct i2c_client *client) { struct og01a1b *og01a1b; + unsigned long freq; int ret; og01a1b = devm_kzalloc(&client->dev, sizeof(*og01a1b), GFP_KERNEL); if (!og01a1b) return -ENOMEM; + og01a1b->dev = &client->dev; + v4l2_i2c_subdev_init(&og01a1b->sd, client, &og01a1b_subdev_ops); - og01a1b->xvclk = devm_clk_get_optional(&client->dev, NULL); - if (IS_ERR(og01a1b->xvclk)) { - ret = PTR_ERR(og01a1b->xvclk); - dev_err(&client->dev, "failed to get xvclk clock: %d\n", ret); - return ret; - } + og01a1b->xvclk = devm_v4l2_sensor_clk_get(og01a1b->dev, NULL); + if (IS_ERR(og01a1b->xvclk)) + return dev_err_probe(og01a1b->dev, PTR_ERR(og01a1b->xvclk), + "failed to get xvclk clock\n"); + + freq = clk_get_rate(og01a1b->xvclk); + if (freq != OG01A1B_MCLK) + return dev_err_probe(og01a1b->dev, -EINVAL, + "external clock %lu is not supported", + freq); ret = og01a1b_check_hwcfg(og01a1b); if (ret) { - dev_err(&client->dev, "failed to check HW configuration: %d", + dev_err(og01a1b->dev, "failed to check HW configuration: %d", ret); return ret; } - og01a1b->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + og01a1b->reset_gpio = devm_gpiod_get_optional(og01a1b->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(og01a1b->reset_gpio)) { - dev_err(&client->dev, "cannot get reset GPIO\n"); + dev_err(og01a1b->dev, "cannot get reset GPIO\n"); return PTR_ERR(og01a1b->reset_gpio); } - og01a1b->avdd = devm_regulator_get_optional(&client->dev, "avdd"); + og01a1b->avdd = devm_regulator_get_optional(og01a1b->dev, "avdd"); if (IS_ERR(og01a1b->avdd)) { ret = PTR_ERR(og01a1b->avdd); if (ret != -ENODEV) { - dev_err_probe(&client->dev, ret, + dev_err_probe(og01a1b->dev, ret, "Failed to get 'avdd' regulator\n"); return ret; } @@ -1114,11 +1099,11 @@ static int og01a1b_probe(struct i2c_client *client) og01a1b->avdd = NULL; } - og01a1b->dovdd = devm_regulator_get_optional(&client->dev, "dovdd"); + og01a1b->dovdd = devm_regulator_get_optional(og01a1b->dev, "dovdd"); if (IS_ERR(og01a1b->dovdd)) { ret = PTR_ERR(og01a1b->dovdd); if (ret != -ENODEV) { - dev_err_probe(&client->dev, ret, + dev_err_probe(og01a1b->dev, ret, "Failed to get 'dovdd' regulator\n"); return ret; } @@ -1126,11 +1111,11 @@ static int og01a1b_probe(struct i2c_client *client) og01a1b->dovdd = NULL; } - og01a1b->dvdd = devm_regulator_get_optional(&client->dev, "dvdd"); + og01a1b->dvdd = devm_regulator_get_optional(og01a1b->dev, "dvdd"); if (IS_ERR(og01a1b->dvdd)) { ret = PTR_ERR(og01a1b->dvdd); if (ret != -ENODEV) { - dev_err_probe(&client->dev, ret, + dev_err_probe(og01a1b->dev, ret, "Failed to get 'dvdd' regulator\n"); return ret; } @@ -1139,13 +1124,13 @@ static int og01a1b_probe(struct i2c_client *client) } /* The sensor must be powered on to read the CHIP_ID register */ - ret = og01a1b_power_on(&client->dev); + ret = og01a1b_power_on(og01a1b->dev); if (ret) return ret; ret = og01a1b_identify_module(og01a1b); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(og01a1b->dev, "failed to find sensor: %d", ret); goto power_off; } @@ -1153,7 +1138,7 @@ static int og01a1b_probe(struct i2c_client *client) og01a1b->cur_mode = &supported_modes[0]; ret = og01a1b_init_controls(og01a1b); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(og01a1b->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -1164,21 +1149,21 @@ static int og01a1b_probe(struct i2c_client *client) og01a1b->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&og01a1b->sd.entity, 1, &og01a1b->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(og01a1b->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&og01a1b->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(og01a1b->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup; } /* Enable runtime PM and turn off the device */ - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(og01a1b->dev); + pm_runtime_enable(og01a1b->dev); + pm_runtime_idle(og01a1b->dev); return 0; @@ -1190,7 +1175,7 @@ probe_error_v4l2_ctrl_handler_free: mutex_destroy(&og01a1b->mutex); power_off: - og01a1b_power_off(&client->dev); + og01a1b_power_off(og01a1b->dev); return ret; } |