diff options
Diffstat (limited to 'drivers/media/i2c/smiapp/smiapp-core.c')
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-core.c | 149 |
1 files changed, 75 insertions, 74 deletions
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 700f433261d0..e6b717b83b18 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -1239,6 +1239,10 @@ static int smiapp_power_on(struct device *dev) sleep = SMIAPP_RESET_DELAY(sensor->hwcfg->ext_clk); usleep_range(sleep, sleep); + mutex_lock(&sensor->mutex); + + sensor->active = true; + /* * Failures to respond to the address change command have been noticed. * Those failures seem to be caused by the sensor requiring a longer @@ -1313,7 +1317,7 @@ static int smiapp_power_on(struct device *dev) rval = smiapp_write(sensor, SMIAPP_REG_U8_DPHY_CTRL, SMIAPP_DPHY_CTRL_UI); if (rval < 0) - return rval; + goto out_cci_addr_fail; rval = smiapp_call_quirk(sensor, post_poweron); if (rval) { @@ -1321,28 +1325,28 @@ static int smiapp_power_on(struct device *dev) goto out_cci_addr_fail; } - /* Are we still initialising...? If yes, return here. */ - if (!sensor->pixel_array) - return 0; + /* Are we still initialising...? If not, proceed with control setup. */ + if (sensor->pixel_array) { + rval = __v4l2_ctrl_handler_setup( + &sensor->pixel_array->ctrl_handler); + if (rval) + goto out_cci_addr_fail; - rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler); - if (rval) - goto out_cci_addr_fail; + rval = __v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); + if (rval) + goto out_cci_addr_fail; - rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); - if (rval) - goto out_cci_addr_fail; + rval = smiapp_update_mode(sensor); + if (rval < 0) + goto out_cci_addr_fail; + } - mutex_lock(&sensor->mutex); - rval = smiapp_update_mode(sensor); mutex_unlock(&sensor->mutex); - if (rval < 0) - goto out_cci_addr_fail; return 0; out_cci_addr_fail: - + mutex_unlock(&sensor->mutex); gpiod_set_value(sensor->xshutdown, 0); clk_disable_unprepare(sensor->ext_clk); @@ -1360,6 +1364,8 @@ static int smiapp_power_off(struct device *dev) struct smiapp_sensor *sensor = container_of(ssd, struct smiapp_sensor, ssds[0]); + mutex_lock(&sensor->mutex); + /* * Currently power/clock to lens are enable/disabled separately * but they are essentially the same signals. So if the sensor is @@ -1372,6 +1378,10 @@ static int smiapp_power_off(struct device *dev) SMIAPP_REG_U8_SOFTWARE_RESET, SMIAPP_SOFTWARE_RESET); + sensor->active = false; + + mutex_unlock(&sensor->mutex); + gpiod_set_value(sensor->xshutdown, 0); clk_disable_unprepare(sensor->ext_clk); usleep_range(5000, 5000); @@ -1381,29 +1391,6 @@ static int smiapp_power_off(struct device *dev) return 0; } -static int smiapp_set_power(struct v4l2_subdev *subdev, int on) -{ - int rval; - - if (!on) { - pm_runtime_mark_last_busy(subdev->dev); - pm_runtime_put_autosuspend(subdev->dev); - - return 0; - } - - rval = pm_runtime_get_sync(subdev->dev); - if (rval >= 0) - return 0; - - if (rval != -EBUSY && rval != -EAGAIN) - pm_runtime_set_active(subdev->dev); - - pm_runtime_put(subdev->dev); - - return rval; -} - /* ----------------------------------------------------------------------------- * Video stream management */ @@ -1560,19 +1547,31 @@ out: static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); int rval; if (sensor->streaming == enable) return 0; if (enable) { + rval = pm_runtime_get_sync(&client->dev); + if (rval < 0) { + if (rval != -EBUSY && rval != -EAGAIN) + pm_runtime_set_active(&client->dev); + pm_runtime_put(&client->dev); + return rval; + } + sensor->streaming = true; + rval = smiapp_start_streaming(sensor); if (rval < 0) sensor->streaming = false; } else { rval = smiapp_stop_streaming(sensor); sensor->streaming = false; + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); } return rval; @@ -2650,7 +2649,6 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) struct smiapp_subdev *ssd = to_smiapp_subdev(sd); struct smiapp_sensor *sensor = ssd->sensor; unsigned int i; - int rval; mutex_lock(&sensor->mutex); @@ -2677,22 +2675,6 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_unlock(&sensor->mutex); - rval = pm_runtime_get_sync(sd->dev); - if (rval >= 0) - return 0; - - if (rval != -EBUSY && rval != -EAGAIN) - pm_runtime_set_active(sd->dev); - pm_runtime_put(sd->dev); - - return rval; -} - -static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - pm_runtime_mark_last_busy(sd->dev); - pm_runtime_put_autosuspend(sd->dev); - return 0; } @@ -2700,10 +2682,6 @@ static const struct v4l2_subdev_video_ops smiapp_video_ops = { .s_stream = smiapp_set_stream, }; -static const struct v4l2_subdev_core_ops smiapp_core_ops = { - .s_power = smiapp_set_power, -}; - static const struct v4l2_subdev_pad_ops smiapp_pad_ops = { .enum_mbus_code = smiapp_enum_mbus_code, .get_fmt = smiapp_get_format, @@ -2718,7 +2696,6 @@ static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = { }; static const struct v4l2_subdev_ops smiapp_ops = { - .core = &smiapp_core_ops, .video = &smiapp_video_ops, .pad = &smiapp_pad_ops, .sensor = &smiapp_sensor_ops, @@ -2732,12 +2709,10 @@ static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = { .registered = smiapp_registered, .unregistered = smiapp_unregistered, .open = smiapp_open, - .close = smiapp_close, }; static const struct v4l2_subdev_internal_ops smiapp_internal_ops = { .open = smiapp_open, - .close = smiapp_close, }; /* ----------------------------------------------------------------------------- @@ -2829,12 +2804,10 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) /* NVM size is not mandatory */ fwnode_property_read_u32(fwnode, "nokia,nvm-size", &hwcfg->nvm_size); - rval = fwnode_property_read_u32(fwnode, "clock-frequency", + rval = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", &hwcfg->ext_clk); - if (rval) { - dev_warn(dev, "can't get clock-frequency\n"); - goto out_err; - } + if (rval) + dev_info(dev, "can't get clock-frequency\n"); dev_dbg(dev, "nvm %d, clk %d, mode %d\n", hwcfg->nvm_size, hwcfg->ext_clk, hwcfg->csi_signalling_mode); @@ -2894,18 +2867,46 @@ static int smiapp_probe(struct i2c_client *client, } sensor->ext_clk = devm_clk_get(&client->dev, NULL); - if (IS_ERR(sensor->ext_clk)) { + if (PTR_ERR(sensor->ext_clk) == -ENOENT) { + dev_info(&client->dev, "no clock defined, continuing...\n"); + sensor->ext_clk = NULL; + } else if (IS_ERR(sensor->ext_clk)) { dev_err(&client->dev, "could not get clock (%ld)\n", PTR_ERR(sensor->ext_clk)); return -EPROBE_DEFER; } - rval = clk_set_rate(sensor->ext_clk, sensor->hwcfg->ext_clk); - if (rval < 0) { - dev_err(&client->dev, - "unable to set clock freq to %u\n", + if (sensor->ext_clk) { + if (sensor->hwcfg->ext_clk) { + unsigned long rate; + + rval = clk_set_rate(sensor->ext_clk, + sensor->hwcfg->ext_clk); + if (rval < 0) { + dev_err(&client->dev, + "unable to set clock freq to %u\n", + sensor->hwcfg->ext_clk); + return rval; + } + + rate = clk_get_rate(sensor->ext_clk); + if (rate != sensor->hwcfg->ext_clk) { + dev_err(&client->dev, + "can't set clock freq, asked for %u but got %lu\n", + sensor->hwcfg->ext_clk, rate); + return rval; + } + } else { + sensor->hwcfg->ext_clk = clk_get_rate(sensor->ext_clk); + dev_dbg(&client->dev, "obtained clock freq %u\n", + sensor->hwcfg->ext_clk); + } + } else if (sensor->hwcfg->ext_clk) { + dev_dbg(&client->dev, "assuming clock freq %u\n", sensor->hwcfg->ext_clk); - return rval; + } else { + dev_err(&client->dev, "unable to obtain clock freq\n"); + return -EINVAL; } sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown", @@ -3092,7 +3093,7 @@ static int smiapp_probe(struct i2c_client *client, if (rval < 0) goto out_media_entity_cleanup; - rval = v4l2_async_register_subdev(&sensor->src->sd); + rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd); if (rval < 0) goto out_media_entity_cleanup; |