xref: /linux/drivers/media/i2c/s5k6a3.c (revision 55a42f78ffd386e01a5404419f8c5ded7db70a21)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Samsung S5K6A3 image sensor driver
4  *
5  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
6  * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
7  */
8 
9 #include <linux/clk.h>
10 #include <linux/delay.h>
11 #include <linux/device.h>
12 #include <linux/err.h>
13 #include <linux/errno.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/i2c.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/regulator/consumer.h>
20 #include <linux/slab.h>
21 #include <linux/videodev2.h>
22 #include <media/v4l2-async.h>
23 #include <media/v4l2-subdev.h>
24 
25 #define S5K6A3_SENSOR_MAX_WIDTH		1412
26 #define S5K6A3_SENSOR_MAX_HEIGHT	1412
27 #define S5K6A3_SENSOR_MIN_WIDTH		32
28 #define S5K6A3_SENSOR_MIN_HEIGHT	32
29 
30 #define S5K6A3_DEFAULT_WIDTH		1296
31 #define S5K6A3_DEFAULT_HEIGHT		732
32 
33 #define S5K6A3_DRV_NAME			"S5K6A3"
34 #define S5K6A3_CLK_NAME			"extclk"
35 #define S5K6A3_DEFAULT_CLK_FREQ		24000000U
36 
37 enum {
38 	S5K6A3_SUPP_VDDA,
39 	S5K6A3_SUPP_VDDIO,
40 	S5K6A3_SUPP_AFVDD,
41 	S5K6A3_NUM_SUPPLIES,
42 };
43 
44 /**
45  * struct s5k6a3 - fimc-is sensor data structure
46  * @dev: pointer to this I2C client device structure
47  * @subdev: the image sensor's v4l2 subdev
48  * @pad: subdev media source pad
49  * @supplies: image sensor's voltage regulator supplies
50  * @gpio_reset: GPIO connected to the sensor's reset pin
51  * @lock: mutex protecting the structure's members below
52  * @format: media bus format at the sensor's source pad
53  * @clock: pointer to &struct clk.
54  * @power_count: stores state if device is powered
55  */
56 struct s5k6a3 {
57 	struct device *dev;
58 	struct v4l2_subdev subdev;
59 	struct media_pad pad;
60 	struct regulator_bulk_data supplies[S5K6A3_NUM_SUPPLIES];
61 	struct gpio_desc *gpio_reset;
62 	struct mutex lock;
63 	struct v4l2_mbus_framefmt format;
64 	struct clk *clock;
65 	int power_count;
66 };
67 
68 static const char * const s5k6a3_supply_names[] = {
69 	[S5K6A3_SUPP_VDDA]	= "svdda",
70 	[S5K6A3_SUPP_VDDIO]	= "svddio",
71 	[S5K6A3_SUPP_AFVDD]	= "afvdd",
72 };
73 
74 static inline struct s5k6a3 *sd_to_s5k6a3(struct v4l2_subdev *sd)
75 {
76 	return container_of(sd, struct s5k6a3, subdev);
77 }
78 
79 static const struct v4l2_mbus_framefmt s5k6a3_formats[] = {
80 	{
81 		.code = MEDIA_BUS_FMT_SGRBG10_1X10,
82 		.colorspace = V4L2_COLORSPACE_SRGB,
83 		.field = V4L2_FIELD_NONE,
84 	}
85 };
86 
87 static const struct v4l2_mbus_framefmt *find_sensor_format(
88 	struct v4l2_mbus_framefmt *mf)
89 {
90 	int i;
91 
92 	for (i = 0; i < ARRAY_SIZE(s5k6a3_formats); i++)
93 		if (mf->code == s5k6a3_formats[i].code)
94 			return &s5k6a3_formats[i];
95 
96 	return &s5k6a3_formats[0];
97 }
98 
99 static int s5k6a3_enum_mbus_code(struct v4l2_subdev *sd,
100 				  struct v4l2_subdev_state *sd_state,
101 				  struct v4l2_subdev_mbus_code_enum *code)
102 {
103 	if (code->index >= ARRAY_SIZE(s5k6a3_formats))
104 		return -EINVAL;
105 
106 	code->code = s5k6a3_formats[code->index].code;
107 	return 0;
108 }
109 
110 static void s5k6a3_try_format(struct v4l2_mbus_framefmt *mf)
111 {
112 	const struct v4l2_mbus_framefmt *fmt;
113 
114 	fmt = find_sensor_format(mf);
115 	mf->code = fmt->code;
116 	mf->field = V4L2_FIELD_NONE;
117 	v4l_bound_align_image(&mf->width, S5K6A3_SENSOR_MIN_WIDTH,
118 			      S5K6A3_SENSOR_MAX_WIDTH, 0,
119 			      &mf->height, S5K6A3_SENSOR_MIN_HEIGHT,
120 			      S5K6A3_SENSOR_MAX_HEIGHT, 0, 0);
121 }
122 
123 static struct v4l2_mbus_framefmt *__s5k6a3_get_format(
124 		struct s5k6a3 *sensor, struct v4l2_subdev_state *sd_state,
125 		u32 pad, enum v4l2_subdev_format_whence which)
126 {
127 	if (which == V4L2_SUBDEV_FORMAT_TRY)
128 		return sd_state ? v4l2_subdev_state_get_format(sd_state, pad) : NULL;
129 
130 	return &sensor->format;
131 }
132 
133 static int s5k6a3_set_fmt(struct v4l2_subdev *sd,
134 				  struct v4l2_subdev_state *sd_state,
135 				  struct v4l2_subdev_format *fmt)
136 {
137 	struct s5k6a3 *sensor = sd_to_s5k6a3(sd);
138 	struct v4l2_mbus_framefmt *mf;
139 
140 	s5k6a3_try_format(&fmt->format);
141 
142 	mf = __s5k6a3_get_format(sensor, sd_state, fmt->pad, fmt->which);
143 	if (mf) {
144 		mutex_lock(&sensor->lock);
145 		*mf = fmt->format;
146 		mutex_unlock(&sensor->lock);
147 	}
148 	return 0;
149 }
150 
151 static int s5k6a3_get_fmt(struct v4l2_subdev *sd,
152 			  struct v4l2_subdev_state *sd_state,
153 			  struct v4l2_subdev_format *fmt)
154 {
155 	struct s5k6a3 *sensor = sd_to_s5k6a3(sd);
156 	struct v4l2_mbus_framefmt *mf;
157 
158 	mf = __s5k6a3_get_format(sensor, sd_state, fmt->pad, fmt->which);
159 
160 	mutex_lock(&sensor->lock);
161 	fmt->format = *mf;
162 	mutex_unlock(&sensor->lock);
163 	return 0;
164 }
165 
166 static const struct v4l2_subdev_pad_ops s5k6a3_pad_ops = {
167 	.enum_mbus_code	= s5k6a3_enum_mbus_code,
168 	.get_fmt	= s5k6a3_get_fmt,
169 	.set_fmt	= s5k6a3_set_fmt,
170 };
171 
172 static int s5k6a3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
173 {
174 	struct v4l2_mbus_framefmt *format = v4l2_subdev_state_get_format(fh->state,
175 									 0);
176 
177 	*format		= s5k6a3_formats[0];
178 	format->width	= S5K6A3_DEFAULT_WIDTH;
179 	format->height	= S5K6A3_DEFAULT_HEIGHT;
180 
181 	return 0;
182 }
183 
184 static const struct v4l2_subdev_internal_ops s5k6a3_sd_internal_ops = {
185 	.open = s5k6a3_open,
186 };
187 
188 static int __s5k6a3_power_on(struct s5k6a3 *sensor)
189 {
190 	int i = S5K6A3_SUPP_VDDA;
191 	int ret;
192 
193 	ret = pm_runtime_get(sensor->dev);
194 	if (ret < 0)
195 		goto error_rpm_put;
196 
197 	ret = regulator_enable(sensor->supplies[i].consumer);
198 	if (ret < 0)
199 		goto error_rpm_put;
200 
201 	ret = clk_prepare_enable(sensor->clock);
202 	if (ret < 0)
203 		goto error_reg_dis;
204 
205 	for (i++; i < S5K6A3_NUM_SUPPLIES; i++) {
206 		ret = regulator_enable(sensor->supplies[i].consumer);
207 		if (ret < 0)
208 			goto error_clk;
209 	}
210 
211 	gpiod_set_value_cansleep(sensor->gpio_reset, 0);
212 	usleep_range(600, 800);
213 	gpiod_set_value_cansleep(sensor->gpio_reset, 1);
214 	usleep_range(600, 800);
215 	gpiod_set_value_cansleep(sensor->gpio_reset, 0);
216 
217 	/* Delay needed for the sensor initialization */
218 	msleep(20);
219 	return 0;
220 
221 error_clk:
222 	clk_disable_unprepare(sensor->clock);
223 error_reg_dis:
224 	for (--i; i >= 0; --i)
225 		regulator_disable(sensor->supplies[i].consumer);
226 error_rpm_put:
227 	pm_runtime_put(sensor->dev);
228 	return ret;
229 }
230 
231 static int __s5k6a3_power_off(struct s5k6a3 *sensor)
232 {
233 	int i;
234 
235 	gpiod_set_value_cansleep(sensor->gpio_reset, 1);
236 
237 	for (i = S5K6A3_NUM_SUPPLIES - 1; i >= 0; i--)
238 		regulator_disable(sensor->supplies[i].consumer);
239 
240 	clk_disable_unprepare(sensor->clock);
241 	pm_runtime_put(sensor->dev);
242 	return 0;
243 }
244 
245 static int s5k6a3_s_power(struct v4l2_subdev *sd, int on)
246 {
247 	struct s5k6a3 *sensor = sd_to_s5k6a3(sd);
248 	int ret = 0;
249 
250 	mutex_lock(&sensor->lock);
251 
252 	if (sensor->power_count == !on) {
253 		if (on)
254 			ret = __s5k6a3_power_on(sensor);
255 		else
256 			ret = __s5k6a3_power_off(sensor);
257 
258 		if (ret == 0)
259 			sensor->power_count += on ? 1 : -1;
260 	}
261 
262 	mutex_unlock(&sensor->lock);
263 	return ret;
264 }
265 
266 static const struct v4l2_subdev_core_ops s5k6a3_core_ops = {
267 	.s_power = s5k6a3_s_power,
268 };
269 
270 static const struct v4l2_subdev_ops s5k6a3_subdev_ops = {
271 	.core = &s5k6a3_core_ops,
272 	.pad = &s5k6a3_pad_ops,
273 };
274 
275 static int s5k6a3_probe(struct i2c_client *client)
276 {
277 	struct device *dev = &client->dev;
278 	struct s5k6a3 *sensor;
279 	struct v4l2_subdev *sd;
280 	int i, ret;
281 
282 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
283 	if (!sensor)
284 		return -ENOMEM;
285 
286 	mutex_init(&sensor->lock);
287 	sensor->dev = dev;
288 
289 	sensor->clock = devm_v4l2_sensor_clk_get_legacy(sensor->dev,
290 							S5K6A3_CLK_NAME, false,
291 							S5K6A3_DEFAULT_CLK_FREQ);
292 	if (IS_ERR(sensor->clock))
293 		return dev_err_probe(sensor->dev, PTR_ERR(sensor->clock),
294 				     "failed to get extclk\n");
295 
296 	sensor->gpio_reset = devm_gpiod_get(dev, NULL, GPIOD_OUT_HIGH);
297 	ret = PTR_ERR_OR_ZERO(sensor->gpio_reset);
298 	if (ret)
299 		return ret;
300 
301 	for (i = 0; i < S5K6A3_NUM_SUPPLIES; i++)
302 		sensor->supplies[i].supply = s5k6a3_supply_names[i];
303 
304 	ret = devm_regulator_bulk_get(&client->dev, S5K6A3_NUM_SUPPLIES,
305 				      sensor->supplies);
306 	if (ret < 0)
307 		return ret;
308 
309 	sd = &sensor->subdev;
310 	v4l2_i2c_subdev_init(sd, client, &s5k6a3_subdev_ops);
311 	sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
312 	sd->internal_ops = &s5k6a3_sd_internal_ops;
313 
314 	sensor->format.code = s5k6a3_formats[0].code;
315 	sensor->format.width = S5K6A3_DEFAULT_WIDTH;
316 	sensor->format.height = S5K6A3_DEFAULT_HEIGHT;
317 
318 	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
319 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
320 	ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad);
321 	if (ret < 0)
322 		return ret;
323 
324 	pm_runtime_no_callbacks(dev);
325 	pm_runtime_enable(dev);
326 
327 	ret = v4l2_async_register_subdev(sd);
328 
329 	if (ret < 0) {
330 		pm_runtime_disable(&client->dev);
331 		media_entity_cleanup(&sd->entity);
332 	}
333 
334 	return ret;
335 }
336 
337 static void s5k6a3_remove(struct i2c_client *client)
338 {
339 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
340 
341 	pm_runtime_disable(&client->dev);
342 	v4l2_async_unregister_subdev(sd);
343 	media_entity_cleanup(&sd->entity);
344 }
345 
346 static const struct i2c_device_id s5k6a3_ids[] = {
347 	{ }
348 };
349 MODULE_DEVICE_TABLE(i2c, s5k6a3_ids);
350 
351 #ifdef CONFIG_OF
352 static const struct of_device_id s5k6a3_of_match[] = {
353 	{ .compatible = "samsung,s5k6a3" },
354 	{ /* sentinel */ }
355 };
356 MODULE_DEVICE_TABLE(of, s5k6a3_of_match);
357 #endif
358 
359 static struct i2c_driver s5k6a3_driver = {
360 	.driver = {
361 		.of_match_table	= of_match_ptr(s5k6a3_of_match),
362 		.name		= S5K6A3_DRV_NAME,
363 	},
364 	.probe		= s5k6a3_probe,
365 	.remove		= s5k6a3_remove,
366 	.id_table	= s5k6a3_ids,
367 };
368 
369 module_i2c_driver(s5k6a3_driver);
370 
371 MODULE_DESCRIPTION("S5K6A3 image sensor subdev driver");
372 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
373 MODULE_LICENSE("GPL v2");
374