Commit 2ec5bfe0 authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab

media: atomisp: gc0310: Switch over to ACPI powermanagement

The DSDT of all Windows BYT / CHT devices which I have seen has proper
ACPI powermagement for the clk and regulators used by the sensors.

So there is no need for the whole custom atomisp_gmin custom code to
disable the ACPI pm and directly poke at the PMIC for this.

Replace all the atomisp_gmin usage with using the new
atomisp_register_sensor_no_gmin() / atomisp_unregister_subdev()
helpers which allow registering a sensor with the atomisp code
without using any of the atomisp_gmin power-management code.

Note eventually these calls should be replaced by the standard
v4l2_async_register_subdev_sensor() mechanism.

But this first requires a bunch of work to the atomisp main code
to make it set the necessary fwnodes up, similar to how
drivers/media/pci/intel/ipu3/cio2-bridge.c does this.
Reviewed-by: default avatarAndy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent 340b4dd6
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Support for GalaxyCore GC0310 VGA camera sensor. * Support for GalaxyCore GC0310 VGA camera sensor.
* *
* Copyright (c) 2013 Intel Corporation. All Rights Reserved. * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
* Copyright (c) 2023 Hans de Goede <hdegoede@redhat.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version * modify it under the terms of the GNU General Public License version
...@@ -26,6 +27,8 @@ ...@@ -26,6 +27,8 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -121,136 +124,6 @@ static const struct v4l2_ctrl_ops ctrl_ops = { ...@@ -121,136 +124,6 @@ static const struct v4l2_ctrl_ops ctrl_ops = {
.s_ctrl = gc0310_s_ctrl, .s_ctrl = gc0310_s_ctrl,
}; };
static int power_ctrl(struct v4l2_subdev *sd, bool flag)
{
int ret = 0;
struct gc0310_device *dev = to_gc0310_sensor(sd);
if (!dev || !dev->platform_data)
return -ENODEV;
if (flag) {
/* The upstream module driver (written to Crystal
* Cove) had this logic to pulse the rails low first.
* This appears to break things on the MRD7 with the
* X-Powers PMIC...
*
* ret = dev->platform_data->v1p8_ctrl(sd, 0);
* ret |= dev->platform_data->v2p8_ctrl(sd, 0);
* mdelay(50);
*/
ret |= dev->platform_data->v1p8_ctrl(sd, 1);
ret |= dev->platform_data->v2p8_ctrl(sd, 1);
usleep_range(10000, 15000);
}
if (!flag || ret) {
ret |= dev->platform_data->v1p8_ctrl(sd, 0);
ret |= dev->platform_data->v2p8_ctrl(sd, 0);
}
return ret;
}
static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
{
int ret;
struct gc0310_device *dev = to_gc0310_sensor(sd);
if (!dev || !dev->platform_data)
return -ENODEV;
/* GPIO0 == "reset" (active low), GPIO1 == "power down" */
if (flag) {
/* Pulse reset, then release power down */
ret = dev->platform_data->gpio0_ctrl(sd, 0);
usleep_range(5000, 10000);
ret |= dev->platform_data->gpio0_ctrl(sd, 1);
usleep_range(10000, 15000);
ret |= dev->platform_data->gpio1_ctrl(sd, 0);
usleep_range(10000, 15000);
} else {
ret = dev->platform_data->gpio1_ctrl(sd, 1);
ret |= dev->platform_data->gpio0_ctrl(sd, 0);
}
return ret;
}
static int power_up(struct v4l2_subdev *sd)
{
struct gc0310_device *dev = to_gc0310_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
if (!dev->platform_data) {
dev_err(&client->dev,
"no camera_sensor_platform_data");
return -ENODEV;
}
/* power control */
ret = power_ctrl(sd, 1);
if (ret)
goto fail_power;
/* flis clock control */
ret = dev->platform_data->flisclk_ctrl(sd, 1);
if (ret)
goto fail_clk;
/* gpio ctrl */
ret = gpio_ctrl(sd, 1);
if (ret) {
ret = gpio_ctrl(sd, 1);
if (ret)
goto fail_gpio;
}
msleep(100);
return 0;
fail_gpio:
dev->platform_data->flisclk_ctrl(sd, 0);
fail_clk:
power_ctrl(sd, 0);
fail_power:
dev_err(&client->dev, "sensor power-up failed\n");
return ret;
}
static int power_down(struct v4l2_subdev *sd)
{
struct gc0310_device *dev = to_gc0310_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0;
if (!dev->platform_data) {
dev_err(&client->dev,
"no camera_sensor_platform_data");
return -ENODEV;
}
/* gpio ctrl */
ret = gpio_ctrl(sd, 0);
if (ret) {
ret = gpio_ctrl(sd, 0);
if (ret)
dev_err(&client->dev, "gpio failed 2\n");
}
ret = dev->platform_data->flisclk_ctrl(sd, 0);
if (ret)
dev_err(&client->dev, "flisclk failed\n");
/* power control */
ret = power_ctrl(sd, 0);
if (ret)
dev_err(&client->dev, "vprog failed.\n");
return ret;
}
static struct v4l2_mbus_framefmt * static struct v4l2_mbus_framefmt *
gc0310_get_pad_format(struct gc0310_device *dev, gc0310_get_pad_format(struct gc0310_device *dev,
struct v4l2_subdev_state *state, struct v4l2_subdev_state *state,
...@@ -344,6 +217,8 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable) ...@@ -344,6 +217,8 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
if (ret < 0) if (ret < 0)
goto error_power_down; goto error_power_down;
msleep(100);
ret = gc0310_write_reg_array(client, gc0310_reset_register, ret = gc0310_write_reg_array(client, gc0310_reset_register,
ARRAY_SIZE(gc0310_reset_register)); ARRAY_SIZE(gc0310_reset_register));
if (ret) if (ret)
...@@ -393,49 +268,16 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable) ...@@ -393,49 +268,16 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
return ret; return ret;
} }
static int gc0310_s_config(struct v4l2_subdev *sd, static int gc0310_s_config(struct v4l2_subdev *sd)
int irq, void *platform_data)
{ {
struct gc0310_device *dev = to_gc0310_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0; int ret;
if (!platform_data)
return -ENODEV;
dev->platform_data =
(struct camera_sensor_platform_data *)platform_data;
mutex_lock(&dev->input_lock);
ret = pm_runtime_get_sync(&client->dev); ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) { if (ret >= 0)
dev_err(&client->dev, "gc0310 power-up err.\n"); ret = gc0310_detect(client);
goto fail_power_on;
}
ret = dev->platform_data->csi_cfg(sd, 1);
if (ret)
goto fail_csi_cfg;
/* config & detect sensor */
ret = gc0310_detect(client);
if (ret) {
dev_err(&client->dev, "gc0310_detect err s_config.\n");
goto fail_csi_cfg;
}
/* turn off sensor, after probed */
pm_runtime_put(&client->dev);
mutex_unlock(&dev->input_lock);
return 0;
fail_csi_cfg:
dev->platform_data->csi_cfg(sd, 0);
fail_power_on:
pm_runtime_put(&client->dev); pm_runtime_put(&client->dev);
mutex_unlock(&dev->input_lock);
return ret; return ret;
} }
...@@ -531,8 +373,7 @@ static void gc0310_remove(struct i2c_client *client) ...@@ -531,8 +373,7 @@ static void gc0310_remove(struct i2c_client *client)
dev_dbg(&client->dev, "gc0310_remove...\n"); dev_dbg(&client->dev, "gc0310_remove...\n");
dev->platform_data->csi_cfg(sd, 0); atomisp_unregister_subdev(sd);
v4l2_device_unregister_subdev(sd); v4l2_device_unregister_subdev(sd);
media_entity_cleanup(&dev->sd.entity); media_entity_cleanup(&dev->sd.entity);
v4l2_ctrl_handler_free(&dev->ctrls.handler); v4l2_ctrl_handler_free(&dev->ctrls.handler);
...@@ -544,34 +385,35 @@ static int gc0310_probe(struct i2c_client *client) ...@@ -544,34 +385,35 @@ static int gc0310_probe(struct i2c_client *client)
{ {
struct gc0310_device *dev; struct gc0310_device *dev;
int ret; int ret;
void *pdata;
dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
if (!dev) if (!dev)
return -ENOMEM; return -ENOMEM;
ret = v4l2_get_acpi_sensor_info(&client->dev, NULL);
if (ret)
return ret;
dev->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(dev->reset))
return dev_err_probe(&client->dev, PTR_ERR(dev->reset),
"getting reset GPIO\n");
dev->powerdown = devm_gpiod_get(&client->dev, "powerdown", GPIOD_OUT_HIGH);
if (IS_ERR(dev->powerdown))
return dev_err_probe(&client->dev, PTR_ERR(dev->powerdown),
"getting powerdown GPIO\n");
mutex_init(&dev->input_lock); mutex_init(&dev->input_lock);
v4l2_i2c_subdev_init(&dev->sd, client, &gc0310_ops); v4l2_i2c_subdev_init(&dev->sd, client, &gc0310_ops);
gc0310_fill_format(&dev->mode.fmt); gc0310_fill_format(&dev->mode.fmt);
pdata = gmin_camera_platform_data(&dev->sd,
ATOMISP_INPUT_FORMAT_RAW_8,
atomisp_bayer_order_grbg);
if (!pdata)
return -EINVAL;
pm_runtime_set_suspended(&client->dev); pm_runtime_set_suspended(&client->dev);
pm_runtime_enable(&client->dev); pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev, 1000); pm_runtime_set_autosuspend_delay(&client->dev, 1000);
pm_runtime_use_autosuspend(&client->dev); pm_runtime_use_autosuspend(&client->dev);
ret = gc0310_s_config(&dev->sd, client->irq, pdata); ret = gc0310_s_config(&dev->sd);
if (ret) {
gc0310_remove(client);
return ret;
}
ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
if (ret) { if (ret) {
gc0310_remove(client); gc0310_remove(client);
return ret; return ret;
...@@ -588,24 +430,42 @@ static int gc0310_probe(struct i2c_client *client) ...@@ -588,24 +430,42 @@ static int gc0310_probe(struct i2c_client *client)
} }
ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
if (ret) if (ret) {
gc0310_remove(client); gc0310_remove(client);
return ret;
}
return ret; ret = atomisp_register_sensor_no_gmin(&dev->sd, 1, ATOMISP_INPUT_FORMAT_RAW_8,
atomisp_bayer_order_grbg);
if (ret) {
gc0310_remove(client);
return ret;
}
return 0;
} }
static int gc0310_suspend(struct device *dev) static int gc0310_suspend(struct device *dev)
{ {
struct v4l2_subdev *sd = dev_get_drvdata(dev); struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct gc0310_device *gc0310_dev = to_gc0310_sensor(sd);
return power_down(sd); gpiod_set_value_cansleep(gc0310_dev->powerdown, 1);
gpiod_set_value_cansleep(gc0310_dev->reset, 1);
return 0;
} }
static int gc0310_resume(struct device *dev) static int gc0310_resume(struct device *dev)
{ {
struct v4l2_subdev *sd = dev_get_drvdata(dev); struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct gc0310_device *gc0310_dev = to_gc0310_sensor(sd);
usleep_range(10000, 15000);
gpiod_set_value_cansleep(gc0310_dev->reset, 0);
usleep_range(10000, 15000);
gpiod_set_value_cansleep(gc0310_dev->powerdown, 0);
return power_up(sd); return 0;
} }
static DEFINE_RUNTIME_DEV_PM_OPS(gc0310_pm_ops, gc0310_suspend, gc0310_resume, NULL); static DEFINE_RUNTIME_DEV_PM_OPS(gc0310_pm_ops, gc0310_suspend, gc0310_resume, NULL);
......
...@@ -92,10 +92,11 @@ struct gc0310_device { ...@@ -92,10 +92,11 @@ struct gc0310_device {
struct v4l2_subdev sd; struct v4l2_subdev sd;
struct media_pad pad; struct media_pad pad;
struct mutex input_lock; struct mutex input_lock;
struct camera_sensor_platform_data *platform_data;
bool is_streaming; bool is_streaming;
struct gpio_desc *reset;
struct gpio_desc *powerdown;
struct gc0310_mode { struct gc0310_mode {
struct v4l2_mbus_framefmt fmt; struct v4l2_mbus_framefmt fmt;
} mode; } mode;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment