diff options
Diffstat (limited to 'drivers/media/i2c/s5k6a3.c')
| -rw-r--r-- | drivers/media/i2c/s5k6a3.c | 85 |
1 files changed, 34 insertions, 51 deletions
diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index 67dcca76f981..ba6477e88da3 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -1,23 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Samsung S5K6A3 image sensor driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/err.h> #include <linux/errno.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_gpio.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -53,17 +50,18 @@ enum { * @gpio_reset: GPIO connected to the sensor's reset pin * @lock: mutex protecting the structure's members below * @format: media bus format at the sensor's source pad + * @clock: pointer to &struct clk. + * @power_count: stores state if device is powered */ struct s5k6a3 { struct device *dev; struct v4l2_subdev subdev; struct media_pad pad; struct regulator_bulk_data supplies[S5K6A3_NUM_SUPPLIES]; - int gpio_reset; + struct gpio_desc *gpio_reset; struct mutex lock; struct v4l2_mbus_framefmt format; struct clk *clock; - u32 clock_frequency; int power_count; }; @@ -99,7 +97,7 @@ static const struct v4l2_mbus_framefmt *find_sensor_format( } static int s5k6a3_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(s5k6a3_formats)) @@ -123,17 +121,17 @@ static void s5k6a3_try_format(struct v4l2_mbus_framefmt *mf) } static struct v4l2_mbus_framefmt *__s5k6a3_get_format( - struct s5k6a3 *sensor, struct v4l2_subdev_pad_config *cfg, + struct s5k6a3 *sensor, struct v4l2_subdev_state *sd_state, u32 pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return cfg ? v4l2_subdev_get_try_format(&sensor->subdev, cfg, pad) : NULL; + return sd_state ? v4l2_subdev_state_get_format(sd_state, pad) : NULL; return &sensor->format; } static int s5k6a3_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct s5k6a3 *sensor = sd_to_s5k6a3(sd); @@ -141,7 +139,7 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd, s5k6a3_try_format(&fmt->format); - mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which); + mf = __s5k6a3_get_format(sensor, sd_state, fmt->pad, fmt->which); if (mf) { mutex_lock(&sensor->lock); *mf = fmt->format; @@ -151,13 +149,13 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd, } static int s5k6a3_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct s5k6a3 *sensor = sd_to_s5k6a3(sd); struct v4l2_mbus_framefmt *mf; - mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which); + mf = __s5k6a3_get_format(sensor, sd_state, fmt->pad, fmt->which); mutex_lock(&sensor->lock); fmt->format = *mf; @@ -173,7 +171,8 @@ static const struct v4l2_subdev_pad_ops s5k6a3_pad_ops = { static int s5k6a3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0); + struct v4l2_mbus_framefmt *format = v4l2_subdev_state_get_format(fh->state, + 0); *format = s5k6a3_formats[0]; format->width = S5K6A3_DEFAULT_WIDTH; @@ -191,13 +190,9 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor) int i = S5K6A3_SUPP_VDDA; int ret; - 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; + goto error_rpm_put; ret = regulator_enable(sensor->supplies[i].consumer); if (ret < 0) @@ -210,19 +205,21 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor) for (i++; i < S5K6A3_NUM_SUPPLIES; i++) { ret = regulator_enable(sensor->supplies[i].consumer); if (ret < 0) - goto error_reg_dis; + goto error_clk; } - gpio_set_value(sensor->gpio_reset, 1); + gpiod_set_value_cansleep(sensor->gpio_reset, 0); usleep_range(600, 800); - gpio_set_value(sensor->gpio_reset, 0); + gpiod_set_value_cansleep(sensor->gpio_reset, 1); usleep_range(600, 800); - gpio_set_value(sensor->gpio_reset, 1); + gpiod_set_value_cansleep(sensor->gpio_reset, 0); /* Delay needed for the sensor initialization */ msleep(20); return 0; +error_clk: + clk_disable_unprepare(sensor->clock); error_reg_dis: for (--i; i >= 0; --i) regulator_disable(sensor->supplies[i].consumer); @@ -235,7 +232,7 @@ static int __s5k6a3_power_off(struct s5k6a3 *sensor) { int i; - gpio_set_value(sensor->gpio_reset, 0); + gpiod_set_value_cansleep(sensor->gpio_reset, 1); for (i = S5K6A3_NUM_SUPPLIES - 1; i >= 0; i--) regulator_disable(sensor->supplies[i].consumer); @@ -275,45 +272,32 @@ static const struct v4l2_subdev_ops s5k6a3_subdev_ops = { .pad = &s5k6a3_pad_ops, }; -static int s5k6a3_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int s5k6a3_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct s5k6a3 *sensor; struct v4l2_subdev *sd; - int gpio, i, ret; + int i, ret; sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); if (!sensor) return -ENOMEM; mutex_init(&sensor->lock); - sensor->gpio_reset = -EINVAL; - sensor->clock = ERR_PTR(-EINVAL); sensor->dev = dev; - sensor->clock = devm_clk_get(sensor->dev, S5K6A3_CLK_NAME); + sensor->clock = devm_v4l2_sensor_clk_get_legacy(sensor->dev, + S5K6A3_CLK_NAME, false, + S5K6A3_DEFAULT_CLK_FREQ); if (IS_ERR(sensor->clock)) - return PTR_ERR(sensor->clock); + return dev_err_probe(sensor->dev, PTR_ERR(sensor->clock), + "failed to get extclk\n"); - gpio = of_get_gpio_flags(dev->of_node, 0, NULL); - if (!gpio_is_valid(gpio)) - return gpio; - - ret = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_LOW, - S5K6A3_DRV_NAME); - if (ret < 0) + sensor->gpio_reset = devm_gpiod_get(dev, NULL, GPIOD_OUT_HIGH); + ret = PTR_ERR_OR_ZERO(sensor->gpio_reset); + if (ret) return ret; - sensor->gpio_reset = gpio; - - if (of_property_read_u32(dev->of_node, "clock-frequency", - &sensor->clock_frequency)) { - sensor->clock_frequency = S5K6A3_DEFAULT_CLK_FREQ; - dev_info(dev, "using default %u Hz clock frequency\n", - sensor->clock_frequency); - } - for (i = 0; i < S5K6A3_NUM_SUPPLIES; i++) sensor->supplies[i].supply = s5k6a3_supply_names[i]; @@ -350,14 +334,13 @@ static int s5k6a3_probe(struct i2c_client *client, return ret; } -static int s5k6a3_remove(struct i2c_client *client) +static void 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; } static const struct i2c_device_id s5k6a3_ids[] = { |
