diff mbox

[v2,4/7] V4L: s5k6a3: Add support for asynchronous subdev registration

Message ID 1377705360-12197-5-git-send-email-s.nawrocki@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

This patch converts the driver to use v4l2 asynchronous subdev
registration API an the clock API to control the external master
clock directly.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/i2c/s5k6a3.c |   36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

Comments

Guennadi Liakhovetski Aug. 28, 2013, 4:21 p.m. UTC | #1
Hi Sylwester,

Just one doubt below

On Wed, 28 Aug 2013, Sylwester Nawrocki wrote:

> This patch converts the driver to use v4l2 asynchronous subdev
> registration API an the clock API to control the external master
> clock directly.
> 
> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  drivers/media/i2c/s5k6a3.c |   36 ++++++++++++++++++++++++++----------
>  1 file changed, 26 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c
> index ba86e24..f65a4f8 100644
> --- a/drivers/media/i2c/s5k6a3.c
> +++ b/drivers/media/i2c/s5k6a3.c

[snip]

> @@ -282,7 +297,7 @@ static int s5k6a3_probe(struct i2c_client *client,
>  	pm_runtime_no_callbacks(dev);
>  	pm_runtime_enable(dev);
>  
> -	return 0;
> +	return v4l2_async_register_subdev(sd);

If the above fails - don't you have to do any clean up? E.g. below you do 
disable runtime PM and clean up the media entity.

Thanks
Guennadi

>  }
>  
>  static int s5k6a3_remove(struct i2c_client *client)
> @@ -290,6 +305,7 @@ static int s5k6a3_remove(struct i2c_client *client)
>  	struct v4l2_subdev *sd = i2c_get_clientdata(client);
>  
>  	pm_runtime_disable(&client->dev);
> +	v4l2_async_unregister_subdev(sd);
>  	media_entity_cleanup(&sd->entity);
>  	return 0;
>  }
> -- 
> 1.7.9.5
> 

---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
On 08/28/2013 06:21 PM, Guennadi Liakhovetski wrote:
> Hi Sylwester,
> 
> Just one doubt below
> 
> On Wed, 28 Aug 2013, Sylwester Nawrocki wrote:
> 
>> > This patch converts the driver to use v4l2 asynchronous subdev
>> > registration API an the clock API to control the external master
>> > clock directly.
>> > 
>> > Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
>> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>> > ---
>> >  drivers/media/i2c/s5k6a3.c |   36 ++++++++++++++++++++++++++----------
>> >  1 file changed, 26 insertions(+), 10 deletions(-)
>> > 
>> > diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c
>> > index ba86e24..f65a4f8 100644
>> > --- a/drivers/media/i2c/s5k6a3.c
>> > +++ b/drivers/media/i2c/s5k6a3.c
> [snip]
> 
>> > @@ -282,7 +297,7 @@ static int s5k6a3_probe(struct i2c_client *client,
>> >  	pm_runtime_no_callbacks(dev);
>> >  	pm_runtime_enable(dev);
>> >  
>> > -	return 0;
>> > +	return v4l2_async_register_subdev(sd);
>
> If the above fails - don't you have to do any clean up? E.g. below you do 
> disable runtime PM and clean up the media entity.

You're right, the clean up steps are missing. Thanks for pointing out,
I've corrected this for the next iteration.

Thanks,
Sylwester
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c
index ba86e24..f65a4f8 100644
--- a/drivers/media/i2c/s5k6a3.c
+++ b/drivers/media/i2c/s5k6a3.c
@@ -34,6 +34,7 @@ 
 #define S5K6A3_DEFAULT_HEIGHT		732
 
 #define S5K6A3_DRV_NAME			"S5K6A3"
+#define S5K6A3_CLK_NAME			"extclk"
 #define S5K6A3_DEFAULT_CLK_FREQ		24000000U
 
 #define S5K6A3_NUM_SUPPLIES		2
@@ -56,6 +57,7 @@  struct s5k6a3 {
 	int gpio_reset;
 	struct mutex lock;
 	struct v4l2_mbus_framefmt format;
+	struct clk *clock;
 	u32 clock_frequency;
 };
 
@@ -181,19 +183,25 @@  static int s5k6a3_s_power(struct v4l2_subdev *sd, int on)
 {
 	struct s5k6a3 *sensor = sd_to_s5k6a3(sd);
 	int gpio = sensor->gpio_reset;
-	int ret;
+	int ret = 0;
 
 	if (on) {
+		ret = clk_set_rate(sensor->clock, sensor->clock_frequency);
+		if (ret < 0)
+			return ret;
+
 		ret = pm_runtime_get(sensor->dev);
 		if (ret < 0)
 			return ret;
 
 		ret = regulator_bulk_enable(S5K6A3_NUM_SUPPLIES,
 					    sensor->supplies);
-		if (ret < 0) {
-			pm_runtime_put(sensor->dev);
-			return ret;
-		}
+		if (ret < 0)
+			goto rpm_put;
+
+		ret = clk_prepare_enable(sensor->clock);
+		if (ret < 0)
+			goto reg_dis;
 
 		if (gpio_is_valid(gpio)) {
 			gpio_set_value(gpio, 1);
@@ -209,10 +217,12 @@  static int s5k6a3_s_power(struct v4l2_subdev *sd, int on)
 		if (gpio_is_valid(gpio))
 			gpio_set_value(gpio, 0);
 
-		ret = regulator_bulk_disable(S5K6A3_NUM_SUPPLIES,
-					     sensor->supplies);
-		if (!ret)
-			pm_runtime_put(sensor->dev);
+		clk_disable_unprepare(sensor->clock);
+reg_dis:
+		regulator_bulk_disable(S5K6A3_NUM_SUPPLIES,
+						sensor->supplies);
+rpm_put:
+		pm_runtime_put(sensor->dev);
 	}
 	return ret;
 }
@@ -240,6 +250,7 @@  static int s5k6a3_probe(struct i2c_client *client,
 
 	mutex_init(&sensor->lock);
 	sensor->gpio_reset = -EINVAL;
+	sensor->clock = ERR_PTR(-EINVAL);
 	sensor->dev = dev;
 
 	gpio = of_get_gpio_flags(dev->of_node, 0, NULL);
@@ -266,6 +277,10 @@  static int s5k6a3_probe(struct i2c_client *client,
 	if (ret < 0)
 		return ret;
 
+	sensor->clock = devm_clk_get(dev, S5K6A3_CLK_NAME);
+	if (IS_ERR(sensor->clock))
+		return -EPROBE_DEFER;
+
 	sd = &sensor->subdev;
 	v4l2_i2c_subdev_init(sd, client, &s5k6a3_subdev_ops);
 	sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -282,7 +297,7 @@  static int s5k6a3_probe(struct i2c_client *client,
 	pm_runtime_no_callbacks(dev);
 	pm_runtime_enable(dev);
 
-	return 0;
+	return v4l2_async_register_subdev(sd);
 }
 
 static int s5k6a3_remove(struct i2c_client *client)
@@ -290,6 +305,7 @@  static int s5k6a3_remove(struct i2c_client *client)
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
 	pm_runtime_disable(&client->dev);
+	v4l2_async_unregister_subdev(sd);
 	media_entity_cleanup(&sd->entity);
 	return 0;
 }