blob: 5b307f26f995ac5b4fa82ac57465c32a7defe0d3 [file] [log] [blame]
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001/*
2 * S5P/EXYNOS4 SoC series camera host interface media device driver
3 *
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -03004 * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
5 * Sylwester Nawrocki <s.nawrocki@samsung.com>
Sylwester Nawrockid3953222011-09-01 06:01:08 -03006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation, either version 2 of the License,
10 * or (at your option) any later version.
11 */
12
13#include <linux/bug.h>
14#include <linux/device.h>
15#include <linux/errno.h>
16#include <linux/i2c.h>
17#include <linux/kernel.h>
18#include <linux/list.h>
19#include <linux/module.h>
Sylwester Nawrockie2985a22013-03-08 12:59:33 -030020#include <linux/of.h>
21#include <linux/of_platform.h>
22#include <linux/of_device.h>
23#include <linux/of_i2c.h>
Sylwester Nawrockid3953222011-09-01 06:01:08 -030024#include <linux/platform_device.h>
25#include <linux/pm_runtime.h>
26#include <linux/types.h>
27#include <linux/slab.h>
Sylwester Nawrocki131b6c62011-08-24 19:25:10 -030028#include <media/v4l2-ctrls.h>
Sylwester Nawrockie2985a22013-03-08 12:59:33 -030029#include <media/v4l2-of.h>
Sylwester Nawrockid3953222011-09-01 06:01:08 -030030#include <media/media-device.h>
Sylwester Nawrockib9ee31e62012-08-14 10:46:58 -030031#include <media/s5p_fimc.h>
Sylwester Nawrockid3953222011-09-01 06:01:08 -030032
Sylwester Nawrocki56fa1a62013-03-24 16:54:25 +010033#include "media-dev.h"
Sylwester Nawrockid3953222011-09-01 06:01:08 -030034#include "fimc-core.h"
Sylwester Nawrockie781bbe32013-03-21 14:49:16 -030035#include "fimc-is.h"
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -030036#include "fimc-lite.h"
Sylwester Nawrockid3953222011-09-01 06:01:08 -030037#include "mipi-csis.h"
38
39static int __fimc_md_set_camclk(struct fimc_md *fmd,
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -030040 struct fimc_source_info *si,
Sylwester Nawrockid3953222011-09-01 06:01:08 -030041 bool on);
42/**
43 * fimc_pipeline_prepare - update pipeline information with subdevice pointers
Sylwester Nawrocki39bb6df62013-03-08 08:58:34 -030044 * @me: media entity terminating the pipeline
Sylwester Nawrockid3953222011-09-01 06:01:08 -030045 *
46 * Caller holds the graph mutex.
47 */
Sylwester Nawrockib9ee31e62012-08-14 10:46:58 -030048static void fimc_pipeline_prepare(struct fimc_pipeline *p,
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -030049 struct media_entity *me)
Sylwester Nawrockid3953222011-09-01 06:01:08 -030050{
Sylwester Nawrockid3953222011-09-01 06:01:08 -030051 struct v4l2_subdev *sd;
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -030052 int i;
Sylwester Nawrockid3953222011-09-01 06:01:08 -030053
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -030054 for (i = 0; i < IDX_MAX; i++)
55 p->subdevs[i] = NULL;
Sylwester Nawrockid3953222011-09-01 06:01:08 -030056
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -030057 while (1) {
Sylwester Nawrocki39bb6df62013-03-08 08:58:34 -030058 struct media_pad *pad = NULL;
Sylwester Nawrockid3953222011-09-01 06:01:08 -030059
Sylwester Nawrocki39bb6df62013-03-08 08:58:34 -030060 /* Find remote source pad */
61 for (i = 0; i < me->num_pads; i++) {
62 struct media_pad *spad = &me->pads[i];
63 if (!(spad->flags & MEDIA_PAD_FL_SINK))
64 continue;
Andrzej Hajda1bddf1b2013-06-03 05:16:13 -030065 pad = media_entity_remote_pad(spad);
Sylwester Nawrocki39bb6df62013-03-08 08:58:34 -030066 if (pad)
67 break;
68 }
69
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -030070 if (pad == NULL ||
71 media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
72 break;
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -030073 sd = media_entity_to_v4l2_subdev(pad->entity);
74
75 switch (sd->grp_id) {
Sylwester Nawrocki588c87b2012-11-27 11:57:42 -030076 case GRP_ID_FIMC_IS_SENSOR:
77 case GRP_ID_SENSOR:
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -030078 p->subdevs[IDX_SENSOR] = sd;
79 break;
Sylwester Nawrocki588c87b2012-11-27 11:57:42 -030080 case GRP_ID_CSIS:
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -030081 p->subdevs[IDX_CSIS] = sd;
82 break;
Sylwester Nawrocki588c87b2012-11-27 11:57:42 -030083 case GRP_ID_FLITE:
Sylwester Nawrocki4af81312012-04-27 05:29:05 -030084 p->subdevs[IDX_FLITE] = sd;
85 break;
Sylwester Nawrocki588c87b2012-11-27 11:57:42 -030086 case GRP_ID_FIMC:
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -030087 /* No need to control FIMC subdev through subdev ops */
88 break;
Sylwester Nawrockie781bbe32013-03-21 14:49:16 -030089 case GRP_ID_FIMC_IS:
90 p->subdevs[IDX_IS_ISP] = sd;
91 break;
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -030092 default:
Sylwester Nawrockie781bbe32013-03-21 14:49:16 -030093 break;
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -030094 }
Sylwester Nawrocki39bb6df62013-03-08 08:58:34 -030095 me = &sd->entity;
96 if (me->num_pads == 1)
97 break;
Sylwester Nawrockid3953222011-09-01 06:01:08 -030098 }
99}
100
101/**
102 * __subdev_set_power - change power state of a single subdev
103 * @sd: subdevice to change power state for
104 * @on: 1 to enable power or 0 to disable
105 *
106 * Return result of s_power subdev operation or -ENXIO if sd argument
107 * is NULL. Return 0 if the subdevice does not implement s_power.
108 */
109static int __subdev_set_power(struct v4l2_subdev *sd, int on)
110{
111 int *use_count;
112 int ret;
113
114 if (sd == NULL)
115 return -ENXIO;
116
117 use_count = &sd->entity.use_count;
118 if (on && (*use_count)++ > 0)
119 return 0;
120 else if (!on && (*use_count == 0 || --(*use_count) > 0))
121 return 0;
122 ret = v4l2_subdev_call(sd, core, s_power, on);
123
124 return ret != -ENOIOCTLCMD ? ret : 0;
125}
126
127/**
128 * fimc_pipeline_s_power - change power state of all pipeline subdevs
129 * @fimc: fimc device terminating the pipeline
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300130 * @state: true to power on, false to power off
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300131 *
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300132 * Needs to be called with the graph mutex held.
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300133 */
Sylwester Nawrockif8bca4f2012-11-20 08:54:22 -0300134static int fimc_pipeline_s_power(struct fimc_pipeline *p, bool on)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300135{
Sylwester Nawrockif8bca4f2012-11-20 08:54:22 -0300136 static const u8 seq[2][IDX_MAX - 1] = {
137 { IDX_IS_ISP, IDX_SENSOR, IDX_CSIS, IDX_FLITE },
138 { IDX_CSIS, IDX_FLITE, IDX_SENSOR, IDX_IS_ISP },
139 };
140 int i, ret = 0;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300141
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300142 if (p->subdevs[IDX_SENSOR] == NULL)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300143 return -ENXIO;
144
Sylwester Nawrockif8bca4f2012-11-20 08:54:22 -0300145 for (i = 0; i < IDX_MAX - 1; i++) {
146 unsigned int idx = seq[on][i];
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300147
Sylwester Nawrockif8bca4f2012-11-20 08:54:22 -0300148 ret = __subdev_set_power(p->subdevs[idx], on);
149
150
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300151 if (ret < 0 && ret != -ENXIO)
Sylwester Nawrockif8bca4f2012-11-20 08:54:22 -0300152 goto error;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300153 }
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300154 return 0;
Sylwester Nawrockif8bca4f2012-11-20 08:54:22 -0300155error:
156 for (; i >= 0; i--) {
157 unsigned int idx = seq[on][i];
158 __subdev_set_power(p->subdevs[idx], !on);
159 }
160 return ret;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300161}
162
163/**
Sylwester Nawrockib9ee31e62012-08-14 10:46:58 -0300164 * __fimc_pipeline_open - update the pipeline information, enable power
165 * of all pipeline subdevs and the sensor clock
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300166 * @me: media entity to start graph walk with
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -0300167 * @prepare: true to walk the current pipeline and acquire all subdevs
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300168 *
Sylwester Nawrocki740ad922012-12-06 10:26:19 -0300169 * Called with the graph mutex held.
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300170 */
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300171static int __fimc_pipeline_open(struct exynos_media_pipeline *ep,
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -0300172 struct media_entity *me, bool prepare)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300173{
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -0300174 struct fimc_md *fmd = entity_to_fimc_mdev(me);
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300175 struct fimc_pipeline *p = to_fimc_pipeline(ep);
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -0300176 struct v4l2_subdev *sd;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300177 int ret;
178
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -0300179 if (WARN_ON(p == NULL || me == NULL))
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300180 return -EINVAL;
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300181
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -0300182 if (prepare)
183 fimc_pipeline_prepare(p, me);
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300184
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -0300185 sd = p->subdevs[IDX_SENSOR];
186 if (sd == NULL)
187 return -EINVAL;
188
189 /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */
190 if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) {
191 ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]);
192 if (ret < 0)
193 return ret;
194 }
195 ret = fimc_md_set_camclk(sd, true);
196 if (ret < 0)
197 goto err_wbclk;
198
199 ret = fimc_pipeline_s_power(p, 1);
200 if (!ret)
201 return 0;
202
203 fimc_md_set_camclk(sd, false);
204
205err_wbclk:
206 if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP])
207 clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]);
208
209 return ret;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300210}
211
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300212/**
Sylwester Nawrockib9ee31e62012-08-14 10:46:58 -0300213 * __fimc_pipeline_close - disable the sensor clock and pipeline power
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300214 * @fimc: fimc device terminating the pipeline
215 *
Sylwester Nawrocki740ad922012-12-06 10:26:19 -0300216 * Disable power of all subdevs and turn the external sensor clock off.
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300217 */
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300218static int __fimc_pipeline_close(struct exynos_media_pipeline *ep)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300219{
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300220 struct fimc_pipeline *p = to_fimc_pipeline(ep);
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -0300221 struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL;
222 struct fimc_md *fmd;
Sylwester Nawrocki36da6fc2013-05-31 11:37:23 -0300223 int ret;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300224
Sylwester Nawrocki36da6fc2013-05-31 11:37:23 -0300225 if (sd == NULL) {
226 pr_warn("%s(): No sensor subdev\n", __func__);
227 return 0;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300228 }
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -0300229
Sylwester Nawrocki36da6fc2013-05-31 11:37:23 -0300230 ret = fimc_pipeline_s_power(p, 0);
231 fimc_md_set_camclk(sd, false);
232
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -0300233 fmd = entity_to_fimc_mdev(&sd->entity);
234
235 /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */
236 if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP])
237 clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]);
238
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300239 return ret == -ENXIO ? 0 : ret;
240}
241
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300242/**
Sylwester Nawrocki8d274e72012-11-13 14:35:22 -0300243 * __fimc_pipeline_s_stream - call s_stream() on pipeline subdevs
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300244 * @pipeline: video pipeline structure
Sylwester Nawrocki8d274e72012-11-13 14:35:22 -0300245 * @on: passed as the s_stream() callback argument
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300246 */
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300247static int __fimc_pipeline_s_stream(struct exynos_media_pipeline *ep, bool on)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300248{
Sylwester Nawrocki8d274e72012-11-13 14:35:22 -0300249 static const u8 seq[2][IDX_MAX] = {
250 { IDX_FIMC, IDX_SENSOR, IDX_IS_ISP, IDX_CSIS, IDX_FLITE },
251 { IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP },
252 };
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300253 struct fimc_pipeline *p = to_fimc_pipeline(ep);
Sylwester Nawrocki8d274e72012-11-13 14:35:22 -0300254 int i, ret = 0;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300255
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300256 if (p->subdevs[IDX_SENSOR] == NULL)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300257 return -ENODEV;
258
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300259 for (i = 0; i < IDX_MAX; i++) {
Sylwester Nawrocki8d274e72012-11-13 14:35:22 -0300260 unsigned int idx = seq[on][i];
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300261
262 ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on);
263
264 if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
Sylwester Nawrocki8d274e72012-11-13 14:35:22 -0300265 goto error;
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300266 }
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -0300267 return 0;
Sylwester Nawrocki8d274e72012-11-13 14:35:22 -0300268error:
269 for (; i >= 0; i--) {
270 unsigned int idx = seq[on][i];
271 v4l2_subdev_call(p->subdevs[idx], video, s_stream, !on);
272 }
273 return ret;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300274}
Sylwester Nawrockib9ee31e62012-08-14 10:46:58 -0300275
276/* Media pipeline operations for the FIMC/FIMC-LITE video device driver */
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300277static const struct exynos_media_pipeline_ops fimc_pipeline_ops = {
Sylwester Nawrocki740ad922012-12-06 10:26:19 -0300278 .open = __fimc_pipeline_open,
279 .close = __fimc_pipeline_close,
280 .set_stream = __fimc_pipeline_s_stream,
Sylwester Nawrockib9ee31e62012-08-14 10:46:58 -0300281};
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300282
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300283static struct exynos_media_pipeline *fimc_md_pipeline_create(
284 struct fimc_md *fmd)
285{
286 struct fimc_pipeline *p;
287
288 p = kzalloc(sizeof(*p), GFP_KERNEL);
289 if (!p)
290 return NULL;
291
292 list_add_tail(&p->list, &fmd->pipelines);
293
294 p->ep.ops = &fimc_pipeline_ops;
295 return &p->ep;
296}
297
298static void fimc_md_pipelines_free(struct fimc_md *fmd)
299{
300 while (!list_empty(&fmd->pipelines)) {
301 struct fimc_pipeline *p;
302
303 p = list_entry(fmd->pipelines.next, typeof(*p), list);
304 list_del(&p->list);
305 kfree(p);
306 }
307}
308
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300309/*
310 * Sensor subdevice helper functions
311 */
312static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd,
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300313 struct fimc_source_info *si)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300314{
315 struct i2c_adapter *adapter;
316 struct v4l2_subdev *sd = NULL;
317
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300318 if (!si || !fmd)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300319 return NULL;
Sylwester Nawrocki88fa8312013-03-20 10:44:39 -0300320 /*
321 * If FIMC bus type is not Writeback FIFO assume it is same
322 * as sensor_bus_type.
323 */
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300324 si->fimc_bus_type = si->sensor_bus_type;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300325
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300326 adapter = i2c_get_adapter(si->i2c_bus_num);
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -0300327 if (!adapter) {
328 v4l2_warn(&fmd->v4l2_dev,
329 "Failed to get I2C adapter %d, deferring probe\n",
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300330 si->i2c_bus_num);
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -0300331 return ERR_PTR(-EPROBE_DEFER);
332 }
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300333 sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter,
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300334 si->board_info, NULL);
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300335 if (IS_ERR_OR_NULL(sd)) {
Sylwester Nawrocki7acde022011-09-13 14:07:09 -0300336 i2c_put_adapter(adapter);
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -0300337 v4l2_warn(&fmd->v4l2_dev,
338 "Failed to acquire subdev %s, deferring probe\n",
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300339 si->board_info->type);
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -0300340 return ERR_PTR(-EPROBE_DEFER);
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300341 }
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300342 v4l2_set_subdev_hostdata(sd, si);
Sylwester Nawrocki588c87b2012-11-27 11:57:42 -0300343 sd->grp_id = GRP_ID_SENSOR;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300344
345 v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice %s\n",
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300346 sd->name);
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300347 return sd;
348}
349
350static void fimc_md_unregister_sensor(struct v4l2_subdev *sd)
351{
352 struct i2c_client *client = v4l2_get_subdevdata(sd);
Sylwester Nawrocki7acde022011-09-13 14:07:09 -0300353 struct i2c_adapter *adapter;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300354
355 if (!client)
356 return;
Sylwester Nawrockie781bbe32013-03-21 14:49:16 -0300357
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300358 v4l2_device_unregister_subdev(sd);
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300359
360 if (!client->dev.of_node) {
361 adapter = client->adapter;
362 i2c_unregister_device(client);
363 if (adapter)
364 i2c_put_adapter(adapter);
365 }
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300366}
367
Sylwester Nawrockie2985a22013-03-08 12:59:33 -0300368#ifdef CONFIG_OF
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300369/* Register I2C client subdev associated with @node. */
370static int fimc_md_of_add_sensor(struct fimc_md *fmd,
371 struct device_node *node, int index)
372{
373 struct fimc_sensor_info *si;
374 struct i2c_client *client;
375 struct v4l2_subdev *sd;
376 int ret;
377
378 if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor)))
379 return -EINVAL;
380 si = &fmd->sensor[index];
381
382 client = of_find_i2c_device_by_node(node);
383 if (!client)
384 return -EPROBE_DEFER;
385
386 device_lock(&client->dev);
387
388 if (!client->driver ||
389 !try_module_get(client->driver->driver.owner)) {
390 ret = -EPROBE_DEFER;
391 v4l2_info(&fmd->v4l2_dev, "No driver found for %s\n",
392 node->full_name);
393 goto dev_put;
394 }
395
396 /* Enable sensor's master clock */
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300397 ret = __fimc_md_set_camclk(fmd, &si->pdata, true);
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300398 if (ret < 0)
399 goto mod_put;
400 sd = i2c_get_clientdata(client);
401
402 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300403 __fimc_md_set_camclk(fmd, &si->pdata, false);
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300404 if (ret < 0)
405 goto mod_put;
406
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300407 v4l2_set_subdev_hostdata(sd, &si->pdata);
Sylwester Nawrockie781bbe32013-03-21 14:49:16 -0300408 if (si->pdata.fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK)
409 sd->grp_id = GRP_ID_FIMC_IS_SENSOR;
410 else
411 sd->grp_id = GRP_ID_SENSOR;
412
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300413 si->subdev = sd;
414 v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n",
415 sd->name, fmd->num_sensors);
416 fmd->num_sensors++;
417
418mod_put:
419 module_put(client->driver->driver.owner);
420dev_put:
421 device_unlock(&client->dev);
422 put_device(&client->dev);
423 return ret;
424}
425
426/* Parse port node and register as a sub-device any sensor specified there. */
427static int fimc_md_parse_port_node(struct fimc_md *fmd,
428 struct device_node *port,
429 unsigned int index)
430{
431 struct device_node *rem, *ep, *np;
432 struct fimc_source_info *pd;
433 struct v4l2_of_endpoint endpoint;
434 int ret;
435 u32 val;
436
437 pd = &fmd->sensor[index].pdata;
438
439 /* Assume here a port node can have only one endpoint node. */
440 ep = of_get_next_child(port, NULL);
441 if (!ep)
442 return 0;
443
444 v4l2_of_parse_endpoint(ep, &endpoint);
445 if (WARN_ON(endpoint.port == 0) || index >= FIMC_MAX_SENSORS)
446 return -EINVAL;
447
448 pd->mux_id = (endpoint.port - 1) & 0x1;
449
450 rem = v4l2_of_get_remote_port_parent(ep);
451 of_node_put(ep);
452 if (rem == NULL) {
453 v4l2_info(&fmd->v4l2_dev, "Remote device at %s not found\n",
454 ep->full_name);
455 return 0;
456 }
457 if (!of_property_read_u32(rem, "samsung,camclk-out", &val))
458 pd->clk_id = val;
459
460 if (!of_property_read_u32(rem, "clock-frequency", &val))
461 pd->clk_frequency = val;
462
463 if (pd->clk_frequency == 0) {
464 v4l2_err(&fmd->v4l2_dev, "Wrong clock frequency at node %s\n",
465 rem->full_name);
466 of_node_put(rem);
467 return -EINVAL;
468 }
469
470 if (fimc_input_is_parallel(endpoint.port)) {
471 if (endpoint.bus_type == V4L2_MBUS_PARALLEL)
472 pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_601;
473 else
474 pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_656;
475 pd->flags = endpoint.bus.parallel.flags;
476 } else if (fimc_input_is_mipi_csi(endpoint.port)) {
477 /*
478 * MIPI CSI-2: only input mux selection and
479 * the sensor's clock frequency is needed.
480 */
481 pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2;
482 } else {
483 v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n",
484 endpoint.port, rem->full_name);
485 }
486 /*
487 * For FIMC-IS handled sensors, that are placed under i2c-isp device
488 * node, FIMC is connected to the FIMC-IS through its ISP Writeback
489 * input. Sensors are attached to the FIMC-LITE hostdata interface
490 * directly or through MIPI-CSIS, depending on the external media bus
491 * used. This needs to be handled in a more reliable way, not by just
492 * checking parent's node name.
493 */
494 np = of_get_parent(rem);
495
496 if (np && !of_node_cmp(np->name, "i2c-isp"))
497 pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK;
498 else
499 pd->fimc_bus_type = pd->sensor_bus_type;
500
501 ret = fimc_md_of_add_sensor(fmd, rem, index);
502 of_node_put(rem);
503
504 return ret;
505}
506
507/* Register all SoC external sub-devices */
508static int fimc_md_of_sensors_register(struct fimc_md *fmd,
509 struct device_node *np)
510{
511 struct device_node *parent = fmd->pdev->dev.of_node;
512 struct device_node *node, *ports;
513 int index = 0;
514 int ret;
515
516 /* Attach sensors linked to MIPI CSI-2 receivers */
517 for_each_available_child_of_node(parent, node) {
518 struct device_node *port;
519
520 if (of_node_cmp(node->name, "csis"))
521 continue;
522 /* The csis node can have only port subnode. */
523 port = of_get_next_child(node, NULL);
524 if (!port)
525 continue;
526
527 ret = fimc_md_parse_port_node(fmd, port, index);
528 if (ret < 0)
529 return ret;
530 index++;
531 }
532
533 /* Attach sensors listed in the parallel-ports node */
534 ports = of_get_child_by_name(parent, "parallel-ports");
535 if (!ports)
536 return 0;
537
538 for_each_child_of_node(ports, node) {
539 ret = fimc_md_parse_port_node(fmd, node, index);
540 if (ret < 0)
541 break;
542 index++;
543 }
544
545 return 0;
546}
547
Sylwester Nawrockie2985a22013-03-08 12:59:33 -0300548static int __of_get_csis_id(struct device_node *np)
549{
550 u32 reg = 0;
551
552 np = of_get_child_by_name(np, "port");
553 if (!np)
554 return -EINVAL;
555 of_property_read_u32(np, "reg", &reg);
556 return reg - FIMC_INPUT_MIPI_CSI2_0;
557}
558#else
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300559#define fimc_md_of_sensors_register(fmd, np) (-ENOSYS)
Sylwester Nawrockie2985a22013-03-08 12:59:33 -0300560#define __of_get_csis_id(np) (-ENOSYS)
561#endif
562
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300563static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
564{
565 struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data;
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300566 struct device_node *of_node = fmd->pdev->dev.of_node;
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300567 int num_clients = 0;
568 int ret, i;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300569
570 /*
571 * Runtime resume one of the FIMC entities to make sure
572 * the sclk_cam clocks are not globally disabled.
573 */
Sylwester Nawrocki3e20c342013-03-21 14:47:17 -0300574 if (!fmd->pmf)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300575 return -ENXIO;
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300576
Sylwester Nawrocki3e20c342013-03-21 14:47:17 -0300577 ret = pm_runtime_get_sync(fmd->pmf);
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300578 if (ret < 0)
579 return ret;
580
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300581 if (of_node) {
582 fmd->num_sensors = 0;
583 ret = fimc_md_of_sensors_register(fmd, of_node);
584 } else if (pdata) {
585 WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor));
586 num_clients = min_t(u32, pdata->num_clients,
587 ARRAY_SIZE(fmd->sensor));
588 fmd->num_sensors = num_clients;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300589
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300590 for (i = 0; i < num_clients; i++) {
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300591 struct fimc_sensor_info *si = &fmd->sensor[i];
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300592 struct v4l2_subdev *sd;
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -0300593
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300594 si->pdata = pdata->source_info[i];
595 ret = __fimc_md_set_camclk(fmd, &si->pdata, true);
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300596 if (ret)
597 break;
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300598 sd = fimc_md_register_sensor(fmd, &si->pdata);
599 ret = __fimc_md_set_camclk(fmd, &si->pdata, false);
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -0300600
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300601 if (IS_ERR(sd)) {
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300602 si->subdev = NULL;
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300603 ret = PTR_ERR(sd);
604 break;
605 }
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300606 si->subdev = sd;
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300607 if (ret)
608 break;
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -0300609 }
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300610 }
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -0300611
Sylwester Nawrocki3e20c342013-03-21 14:47:17 -0300612 pm_runtime_put(fmd->pmf);
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300613 return ret;
614}
615
616/*
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300617 * MIPI-CSIS, FIMC and FIMC-LITE platform devices registration.
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300618 */
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300619
620static int register_fimc_lite_entity(struct fimc_md *fmd,
621 struct fimc_lite *fimc_lite)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300622{
Sachin Kamat8163ec02012-10-25 10:56:00 -0300623 struct v4l2_subdev *sd;
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300624 struct exynos_media_pipeline *ep;
Sylwester Nawrockiafd73482012-10-25 10:48:44 -0300625 int ret;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300626
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300627 if (WARN_ON(fimc_lite->index >= FIMC_LITE_MAX_DEVS ||
628 fmd->fimc_lite[fimc_lite->index]))
629 return -EBUSY;
630
631 sd = &fimc_lite->subdev;
632 sd->grp_id = GRP_ID_FLITE;
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300633
634 ep = fimc_md_pipeline_create(fmd);
635 if (!ep)
636 return -ENOMEM;
637
638 v4l2_set_subdev_hostdata(sd, ep);
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300639
640 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
641 if (!ret)
642 fmd->fimc_lite[fimc_lite->index] = fimc_lite;
643 else
644 v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.LITE%d\n",
645 fimc_lite->index);
646 return ret;
647}
648
649static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc)
650{
651 struct v4l2_subdev *sd;
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300652 struct exynos_media_pipeline *ep;
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300653 int ret;
654
655 if (WARN_ON(fimc->id >= FIMC_MAX_DEVS || fmd->fimc[fimc->id]))
656 return -EBUSY;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300657
Sachin Kamat8163ec02012-10-25 10:56:00 -0300658 sd = &fimc->vid_cap.subdev;
Sylwester Nawrocki588c87b2012-11-27 11:57:42 -0300659 sd->grp_id = GRP_ID_FIMC;
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300660
661 ep = fimc_md_pipeline_create(fmd);
662 if (!ep)
663 return -ENOMEM;
664
665 v4l2_set_subdev_hostdata(sd, ep);
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -0300666
667 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300668 if (!ret) {
Sylwester Nawrocki3e20c342013-03-21 14:47:17 -0300669 if (!fmd->pmf && fimc->pdev)
670 fmd->pmf = &fimc->pdev->dev;
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300671 fmd->fimc[fimc->id] = fimc;
672 fimc->vid_cap.user_subdev_api = fmd->user_subdev_api;
673 } else {
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -0300674 v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n",
675 fimc->id, ret);
676 }
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300677 return ret;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300678}
679
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300680static int register_csis_entity(struct fimc_md *fmd,
681 struct platform_device *pdev,
682 struct v4l2_subdev *sd)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300683{
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300684 struct device_node *node = pdev->dev.of_node;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300685 int id, ret;
686
Sylwester Nawrockie2985a22013-03-08 12:59:33 -0300687 id = node ? __of_get_csis_id(node) : max(0, pdev->id);
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300688
Sylwester Nawrockie2985a22013-03-08 12:59:33 -0300689 if (WARN_ON(id < 0 || id >= CSIS_MAX_ENTITIES))
690 return -ENOENT;
691
692 if (WARN_ON(fmd->csis[id].sd))
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300693 return -EBUSY;
694
Sylwester Nawrocki588c87b2012-11-27 11:57:42 -0300695 sd->grp_id = GRP_ID_CSIS;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300696 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
Sylwester Nawrockiafd73482012-10-25 10:48:44 -0300697 if (!ret)
698 fmd->csis[id].sd = sd;
699 else
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300700 v4l2_err(&fmd->v4l2_dev,
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300701 "Failed to register MIPI-CSIS.%d (%d)\n", id, ret);
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300702 return ret;
703}
704
Sylwester Nawrockie781bbe32013-03-21 14:49:16 -0300705static int register_fimc_is_entity(struct fimc_md *fmd, struct fimc_is *is)
706{
707 struct v4l2_subdev *sd = &is->isp.subdev;
708 int ret;
709
710 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
711 if (ret) {
712 v4l2_err(&fmd->v4l2_dev,
713 "Failed to register FIMC-ISP (%d)\n", ret);
714 return ret;
715 }
716
717 fmd->fimc_is = is;
718 return 0;
719}
720
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300721static int fimc_md_register_platform_entity(struct fimc_md *fmd,
722 struct platform_device *pdev,
723 int plat_entity)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300724{
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300725 struct device *dev = &pdev->dev;
726 int ret = -EPROBE_DEFER;
727 void *drvdata;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300728
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300729 /* Lock to ensure dev->driver won't change. */
730 device_lock(dev);
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -0300731
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300732 if (!dev->driver || !try_module_get(dev->driver->owner))
733 goto dev_unlock;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300734
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300735 drvdata = dev_get_drvdata(dev);
736 /* Some subdev didn't probe succesfully id drvdata is NULL */
737 if (drvdata) {
738 switch (plat_entity) {
739 case IDX_FIMC:
740 ret = register_fimc_entity(fmd, drvdata);
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -0300741 break;
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300742 case IDX_FLITE:
743 ret = register_fimc_lite_entity(fmd, drvdata);
744 break;
745 case IDX_CSIS:
746 ret = register_csis_entity(fmd, pdev, drvdata);
747 break;
Sylwester Nawrockie781bbe32013-03-21 14:49:16 -0300748 case IDX_IS_ISP:
749 ret = register_fimc_is_entity(fmd, drvdata);
750 break;
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300751 default:
752 ret = -ENODEV;
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -0300753 }
754 }
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300755
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300756 module_put(dev->driver->owner);
757dev_unlock:
758 device_unlock(dev);
759 if (ret == -EPROBE_DEFER)
760 dev_info(&fmd->pdev->dev, "deferring %s device registration\n",
761 dev_name(dev));
762 else if (ret < 0)
763 dev_err(&fmd->pdev->dev, "%s device registration failed (%d)\n",
764 dev_name(dev), ret);
765 return ret;
766}
767
768static int fimc_md_pdev_match(struct device *dev, void *data)
769{
770 struct platform_device *pdev = to_platform_device(dev);
771 int plat_entity = -1;
772 int ret;
773 char *p;
774
775 if (!get_device(dev))
776 return -ENODEV;
777
778 if (!strcmp(pdev->name, CSIS_DRIVER_NAME)) {
779 plat_entity = IDX_CSIS;
780 } else if (!strcmp(pdev->name, FIMC_LITE_DRV_NAME)) {
781 plat_entity = IDX_FLITE;
782 } else {
783 p = strstr(pdev->name, "fimc");
784 if (p && *(p + 4) == 0)
785 plat_entity = IDX_FIMC;
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -0300786 }
787
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300788 if (plat_entity >= 0)
789 ret = fimc_md_register_platform_entity(data, pdev,
790 plat_entity);
791 put_device(dev);
792 return 0;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300793}
794
Sylwester Nawrockie2985a22013-03-08 12:59:33 -0300795/* Register FIMC, FIMC-LITE and CSIS media entities */
796#ifdef CONFIG_OF
797static int fimc_md_register_of_platform_entities(struct fimc_md *fmd,
798 struct device_node *parent)
799{
800 struct device_node *node;
801 int ret = 0;
802
803 for_each_available_child_of_node(parent, node) {
804 struct platform_device *pdev;
805 int plat_entity = -1;
806
807 pdev = of_find_device_by_node(node);
808 if (!pdev)
809 continue;
810
811 /* If driver of any entity isn't ready try all again later. */
812 if (!strcmp(node->name, CSIS_OF_NODE_NAME))
813 plat_entity = IDX_CSIS;
Sylwester Nawrockie781bbe32013-03-21 14:49:16 -0300814 else if (!strcmp(node->name, FIMC_IS_OF_NODE_NAME))
815 plat_entity = IDX_IS_ISP;
Sylwester Nawrockie2985a22013-03-08 12:59:33 -0300816 else if (!strcmp(node->name, FIMC_LITE_OF_NODE_NAME))
817 plat_entity = IDX_FLITE;
818 else if (!strcmp(node->name, FIMC_OF_NODE_NAME) &&
819 !of_property_read_bool(node, "samsung,lcd-wb"))
820 plat_entity = IDX_FIMC;
821
822 if (plat_entity >= 0)
823 ret = fimc_md_register_platform_entity(fmd, pdev,
824 plat_entity);
825 put_device(&pdev->dev);
826 if (ret < 0)
827 break;
828 }
829
830 return ret;
831}
832#else
833#define fimc_md_register_of_platform_entities(fmd, node) (-ENOSYS)
834#endif
835
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300836static void fimc_md_unregister_entities(struct fimc_md *fmd)
837{
838 int i;
839
840 for (i = 0; i < FIMC_MAX_DEVS; i++) {
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300841 struct fimc_dev *dev = fmd->fimc[i];
842 if (dev == NULL)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300843 continue;
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300844 v4l2_device_unregister_subdev(&dev->vid_cap.subdev);
845 dev->vid_cap.ve.pipe = NULL;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300846 fmd->fimc[i] = NULL;
847 }
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300848 for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300849 struct fimc_lite *dev = fmd->fimc_lite[i];
850 if (dev == NULL)
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300851 continue;
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -0300852 v4l2_device_unregister_subdev(&dev->subdev);
853 dev->ve.pipe = NULL;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300854 fmd->fimc_lite[i] = NULL;
855 }
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300856 for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
857 if (fmd->csis[i].sd == NULL)
858 continue;
859 v4l2_device_unregister_subdev(fmd->csis[i].sd);
860 fmd->csis[i].sd = NULL;
861 }
862 for (i = 0; i < fmd->num_sensors; i++) {
863 if (fmd->sensor[i].subdev == NULL)
864 continue;
865 fimc_md_unregister_sensor(fmd->sensor[i].subdev);
866 fmd->sensor[i].subdev = NULL;
867 }
Sylwester Nawrockie41a35c2013-04-18 09:05:54 -0300868
869 if (fmd->fimc_is)
870 v4l2_device_unregister_subdev(&fmd->fimc_is->isp.subdev);
871
Sylwester Nawrocki7b43a6f2012-12-12 08:16:05 -0300872 v4l2_info(&fmd->v4l2_dev, "Unregistered all entities\n");
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300873}
874
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300875/**
876 * __fimc_md_create_fimc_links - create links to all FIMC entities
877 * @fmd: fimc media device
878 * @source: the source entity to create links to all fimc entities from
879 * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null
880 * @pad: the source entity pad index
Sylwester Nawrockid0da3c32012-05-16 13:08:30 -0300881 * @link_mask: bitmask of the fimc devices for which link should be enabled
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300882 */
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300883static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
884 struct media_entity *source,
885 struct v4l2_subdev *sensor,
Sylwester Nawrockid0da3c32012-05-16 13:08:30 -0300886 int pad, int link_mask)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300887{
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300888 struct fimc_source_info *si = NULL;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300889 struct media_entity *sink;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300890 unsigned int flags = 0;
Sylwester Nawrockif998bb72012-11-27 13:29:48 -0300891 int i, ret = 0;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300892
Sylwester Nawrockif998bb72012-11-27 13:29:48 -0300893 if (sensor) {
894 si = v4l2_get_subdev_hostdata(sensor);
895 /* Skip direct FIMC links in the logical FIMC-IS sensor path */
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300896 if (si && si->fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK)
Sylwester Nawrockif998bb72012-11-27 13:29:48 -0300897 ret = 1;
898 }
899
900 for (i = 0; !ret && i < FIMC_MAX_DEVS; i++) {
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300901 if (!fmd->fimc[i])
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300902 continue;
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300903 /*
904 * Some FIMC variants are not fitted with camera capture
905 * interface. Skip creating a link from sensor for those.
906 */
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300907 if (!fmd->fimc[i]->variant->has_cam_if)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300908 continue;
909
Sylwester Nawrockid0da3c32012-05-16 13:08:30 -0300910 flags = ((1 << i) & link_mask) ? MEDIA_LNK_FL_ENABLED : 0;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300911
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -0300912 sink = &fmd->fimc[i]->vid_cap.subdev.entity;
Sylwester Nawrocki237e0262011-08-24 20:35:30 -0300913 ret = media_entity_create_link(source, pad, sink,
Sylwester Nawrocki88fa8312013-03-20 10:44:39 -0300914 FIMC_SD_PAD_SINK_CAM, flags);
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300915 if (ret)
916 return ret;
917
Sylwester Nawrocki237e0262011-08-24 20:35:30 -0300918 /* Notify FIMC capture subdev entity */
919 ret = media_entity_call(sink, link_setup, &sink->pads[0],
920 &source->pads[pad], flags);
921 if (ret)
922 break;
923
Sylwester Nawrocki542fb082012-10-25 05:48:19 -0300924 v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n",
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300925 source->name, flags ? '=' : '-', sink->name);
926
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300927 if (flags == 0 || sensor == NULL)
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300928 continue;
Sylwester Nawrockif998bb72012-11-27 13:29:48 -0300929
930 if (!WARN_ON(si == NULL)) {
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300931 unsigned long irq_flags;
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300932 struct fimc_sensor_info *inf = source_to_sensor_info(si);
933
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300934 spin_lock_irqsave(&fmd->slock, irq_flags);
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -0300935 inf->host = fmd->fimc[i];
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300936 spin_unlock_irqrestore(&fmd->slock, irq_flags);
937 }
938 }
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300939
940 for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
941 if (!fmd->fimc_lite[i])
942 continue;
943
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300944 sink = &fmd->fimc_lite[i]->subdev.entity;
945 ret = media_entity_create_link(source, pad, sink,
Sylwester Nawrockif998bb72012-11-27 13:29:48 -0300946 FLITE_SD_PAD_SINK, 0);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300947 if (ret)
948 return ret;
949
950 /* Notify FIMC-LITE subdev entity */
951 ret = media_entity_call(sink, link_setup, &sink->pads[0],
Sylwester Nawrockif998bb72012-11-27 13:29:48 -0300952 &source->pads[pad], 0);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300953 if (ret)
954 break;
955
Sylwester Nawrockif998bb72012-11-27 13:29:48 -0300956 v4l2_info(&fmd->v4l2_dev, "created link [%s] -> [%s]\n",
957 source->name, sink->name);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300958 }
Sylwester Nawrockid3953222011-09-01 06:01:08 -0300959 return 0;
960}
961
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300962/* Create links from FIMC-LITE source pads to other entities */
963static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
964{
965 struct media_entity *source, *sink;
Sylwester Nawrockia26860b2012-12-05 13:43:05 -0300966 int i, ret = 0;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300967
968 for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
969 struct fimc_lite *fimc = fmd->fimc_lite[i];
Sylwester Nawrockif998bb72012-11-27 13:29:48 -0300970
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300971 if (fimc == NULL)
972 continue;
Sylwester Nawrockif998bb72012-11-27 13:29:48 -0300973
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300974 source = &fimc->subdev.entity;
Sylwester Nawrockibc7584b2013-05-31 11:37:18 -0300975 sink = &fimc->ve.vdev.entity;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300976 /* FIMC-LITE's subdev and video node */
Sylwester Nawrocki6319d6a2012-11-28 15:41:01 -0300977 ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_DMA,
Sylwester Nawrockif998bb72012-11-27 13:29:48 -0300978 sink, 0, 0);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -0300979 if (ret)
980 break;
Sylwester Nawrockif998bb72012-11-27 13:29:48 -0300981 /* Link from FIMC-LITE to IS-ISP subdev */
982 sink = &fmd->fimc_is->isp.subdev.entity;
983 ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_ISP,
984 sink, 0, 0);
985 if (ret)
986 break;
987 }
988
989 return ret;
990}
991
992/* Create FIMC-IS links */
993static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd)
994{
995 struct media_entity *source, *sink;
996 int i, ret;
997
998 source = &fmd->fimc_is->isp.subdev.entity;
999
1000 for (i = 0; i < FIMC_MAX_DEVS; i++) {
1001 if (fmd->fimc[i] == NULL)
1002 continue;
1003
1004 /* Link from IS-ISP subdev to FIMC */
1005 sink = &fmd->fimc[i]->vid_cap.subdev.entity;
1006 ret = media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_FIFO,
1007 sink, FIMC_SD_PAD_SINK_FIFO, 0);
1008 if (ret)
1009 return ret;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001010 }
1011
1012 return ret;
1013}
1014
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001015/**
1016 * fimc_md_create_links - create default links between registered entities
1017 *
1018 * Parallel interface sensor entities are connected directly to FIMC capture
1019 * entities. The sensors using MIPI CSIS bus are connected through immutable
1020 * link with CSI receiver entity specified by mux_id. Any registered CSIS
1021 * entity has a link to each registered FIMC capture entity. Enabled links
1022 * are created by default between each subsequent registered sensor and
1023 * subsequent FIMC capture entity. The number of default active links is
1024 * determined by the number of available sensors or FIMC entities,
1025 * whichever is less.
1026 */
1027static int fimc_md_create_links(struct fimc_md *fmd)
1028{
Sylwester Nawrockia8697ec2012-12-05 13:40:04 -03001029 struct v4l2_subdev *csi_sensors[CSIS_MAX_ENTITIES] = { NULL };
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001030 struct v4l2_subdev *sensor, *csis;
Sylwester Nawrocki56bc9112013-02-01 15:00:40 -03001031 struct fimc_source_info *pdata;
Sylwester Nawrocki237e0262011-08-24 20:35:30 -03001032 struct media_entity *source, *sink;
Sylwester Nawrockid0da3c32012-05-16 13:08:30 -03001033 int i, pad, fimc_id = 0, ret = 0;
1034 u32 flags, link_mask = 0;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001035
1036 for (i = 0; i < fmd->num_sensors; i++) {
1037 if (fmd->sensor[i].subdev == NULL)
1038 continue;
1039
1040 sensor = fmd->sensor[i].subdev;
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -03001041 pdata = v4l2_get_subdev_hostdata(sensor);
1042 if (!pdata)
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001043 continue;
1044
1045 source = NULL;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001046
Sylwester Nawrocki56bc9112013-02-01 15:00:40 -03001047 switch (pdata->sensor_bus_type) {
1048 case FIMC_BUS_TYPE_MIPI_CSI2:
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001049 if (WARN(pdata->mux_id >= CSIS_MAX_ENTITIES,
1050 "Wrong CSI channel id: %d\n", pdata->mux_id))
1051 return -EINVAL;
1052
1053 csis = fmd->csis[pdata->mux_id].sd;
1054 if (WARN(csis == NULL,
1055 "MIPI-CSI interface specified "
1056 "but s5p-csis module is not loaded!\n"))
Sylwester Nawrockid12392e2011-10-20 05:15:59 -03001057 return -EINVAL;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001058
Andrzej Hajda1c9f5bd2012-11-22 12:13:27 -03001059 pad = sensor->entity.num_pads - 1;
1060 ret = media_entity_create_link(&sensor->entity, pad,
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001061 &csis->entity, CSIS_PAD_SINK,
1062 MEDIA_LNK_FL_IMMUTABLE |
1063 MEDIA_LNK_FL_ENABLED);
1064 if (ret)
1065 return ret;
1066
Sylwester Nawrocki969e8772012-12-07 16:40:08 -03001067 v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]\n",
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001068 sensor->entity.name, csis->entity.name);
1069
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001070 source = NULL;
Sylwester Nawrocki5d33ee92012-08-16 14:06:41 -03001071 csi_sensors[pdata->mux_id] = sensor;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001072 break;
1073
Sylwester Nawrocki56bc9112013-02-01 15:00:40 -03001074 case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656:
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001075 source = &sensor->entity;
1076 pad = 0;
1077 break;
1078
1079 default:
1080 v4l2_err(&fmd->v4l2_dev, "Wrong bus_type: %x\n",
Sylwester Nawrocki56bc9112013-02-01 15:00:40 -03001081 pdata->sensor_bus_type);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001082 return -EINVAL;
1083 }
1084 if (source == NULL)
1085 continue;
1086
Sylwester Nawrockid0da3c32012-05-16 13:08:30 -03001087 link_mask = 1 << fimc_id++;
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001088 ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor,
Sylwester Nawrockid0da3c32012-05-16 13:08:30 -03001089 pad, link_mask);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001090 }
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001091
Sylwester Nawrockia8697ec2012-12-05 13:40:04 -03001092 for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001093 if (fmd->csis[i].sd == NULL)
1094 continue;
Sylwester Nawrockif998bb72012-11-27 13:29:48 -03001095
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001096 source = &fmd->csis[i].sd->entity;
1097 pad = CSIS_PAD_SOURCE;
Sylwester Nawrocki5d33ee92012-08-16 14:06:41 -03001098 sensor = csi_sensors[i];
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001099
Sylwester Nawrockid0da3c32012-05-16 13:08:30 -03001100 link_mask = 1 << fimc_id++;
Sylwester Nawrocki5d33ee92012-08-16 14:06:41 -03001101 ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor,
Sylwester Nawrockid0da3c32012-05-16 13:08:30 -03001102 pad, link_mask);
Sylwester Nawrocki4af81312012-04-27 05:29:05 -03001103 }
1104
Sylwester Nawrocki237e0262011-08-24 20:35:30 -03001105 /* Create immutable links between each FIMC's subdev and video node */
1106 flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
1107 for (i = 0; i < FIMC_MAX_DEVS; i++) {
1108 if (!fmd->fimc[i])
1109 continue;
Sylwester Nawrockif998bb72012-11-27 13:29:48 -03001110
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -03001111 source = &fmd->fimc[i]->vid_cap.subdev.entity;
Sylwester Nawrockibc7584b2013-05-31 11:37:18 -03001112 sink = &fmd->fimc[i]->vid_cap.ve.vdev.entity;
Sylwester Nawrockif998bb72012-11-27 13:29:48 -03001113
Sylwester Nawrocki237e0262011-08-24 20:35:30 -03001114 ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
1115 sink, 0, flags);
1116 if (ret)
1117 break;
1118 }
1119
Sylwester Nawrockif998bb72012-11-27 13:29:48 -03001120 ret = __fimc_md_create_flite_source_links(fmd);
1121 if (ret < 0)
1122 return ret;
1123
1124 if (fmd->use_isp)
1125 ret = __fimc_md_create_fimc_is_links(fmd);
1126
1127 return ret;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001128}
1129
1130/*
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -03001131 * The peripheral sensor and CAM_BLK (PIXELASYNCMx) clocks management.
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001132 */
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001133static void fimc_md_put_clocks(struct fimc_md *fmd)
1134{
1135 int i = FIMC_MAX_CAMCLKS;
1136
1137 while (--i >= 0) {
Sylwester Nawrocki0e23cbb2013-01-18 15:34:37 -03001138 if (IS_ERR(fmd->camclk[i].clock))
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001139 continue;
Sylwester Nawrocki0e23cbb2013-01-18 15:34:37 -03001140 clk_unprepare(fmd->camclk[i].clock);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001141 clk_put(fmd->camclk[i].clock);
Sylwester Nawrocki0e23cbb2013-01-18 15:34:37 -03001142 fmd->camclk[i].clock = ERR_PTR(-EINVAL);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001143 }
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -03001144
1145 /* Writeback (PIXELASYNCMx) clocks */
1146 for (i = 0; i < FIMC_MAX_WBCLKS; i++) {
1147 if (IS_ERR(fmd->wbclk[i]))
1148 continue;
1149 clk_put(fmd->wbclk[i]);
1150 fmd->wbclk[i] = ERR_PTR(-EINVAL);
1151 }
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001152}
1153
Sylwester Nawrocki0e23cbb2013-01-18 15:34:37 -03001154static int fimc_md_get_clocks(struct fimc_md *fmd)
1155{
1156 struct device *dev = NULL;
1157 char clk_name[32];
1158 struct clk *clock;
1159 int ret, i;
1160
1161 for (i = 0; i < FIMC_MAX_CAMCLKS; i++)
1162 fmd->camclk[i].clock = ERR_PTR(-EINVAL);
1163
1164 if (fmd->pdev->dev.of_node)
1165 dev = &fmd->pdev->dev;
1166
1167 for (i = 0; i < FIMC_MAX_CAMCLKS; i++) {
1168 snprintf(clk_name, sizeof(clk_name), "sclk_cam%u", i);
1169 clock = clk_get(dev, clk_name);
1170
1171 if (IS_ERR(clock)) {
1172 dev_err(&fmd->pdev->dev, "Failed to get clock: %s\n",
1173 clk_name);
1174 ret = PTR_ERR(clock);
1175 break;
1176 }
1177 ret = clk_prepare(clock);
1178 if (ret < 0) {
1179 clk_put(clock);
1180 fmd->camclk[i].clock = ERR_PTR(-EINVAL);
1181 break;
1182 }
1183 fmd->camclk[i].clock = clock;
1184 }
1185 if (ret)
1186 fimc_md_put_clocks(fmd);
1187
Sylwester Nawrocki056f4f32013-03-21 14:43:17 -03001188 if (!fmd->use_isp)
1189 return 0;
1190 /*
1191 * For now get only PIXELASYNCM1 clock (Writeback B/ISP),
1192 * leave PIXELASYNCM0 out for the LCD Writeback driver.
1193 */
1194 fmd->wbclk[CLK_IDX_WB_A] = ERR_PTR(-EINVAL);
1195
1196 for (i = CLK_IDX_WB_B; i < FIMC_MAX_WBCLKS; i++) {
1197 snprintf(clk_name, sizeof(clk_name), "pxl_async%u", i);
1198 clock = clk_get(dev, clk_name);
1199 if (IS_ERR(clock)) {
1200 v4l2_err(&fmd->v4l2_dev, "Failed to get clock: %s\n",
1201 clk_name);
1202 ret = PTR_ERR(clock);
1203 break;
1204 }
1205 fmd->wbclk[i] = clock;
1206 }
1207 if (ret)
1208 fimc_md_put_clocks(fmd);
1209
Sylwester Nawrocki0e23cbb2013-01-18 15:34:37 -03001210 return ret;
1211}
1212
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001213static int __fimc_md_set_camclk(struct fimc_md *fmd,
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -03001214 struct fimc_source_info *si,
Sylwester Nawrockie3fc82e2012-05-17 14:22:10 -03001215 bool on)
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001216{
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001217 struct fimc_camclk_info *camclk;
1218 int ret = 0;
1219
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -03001220 if (WARN_ON(si->clk_id >= FIMC_MAX_CAMCLKS) || !fmd || !fmd->pmf)
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001221 return -EINVAL;
1222
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -03001223 camclk = &fmd->camclk[si->clk_id];
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001224
Sylwester Nawrockie3fc82e2012-05-17 14:22:10 -03001225 dbg("camclk %d, f: %lu, use_count: %d, on: %d",
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -03001226 si->clk_id, si->clk_frequency, camclk->use_count, on);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001227
1228 if (on) {
1229 if (camclk->use_count > 0 &&
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -03001230 camclk->frequency != si->clk_frequency)
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001231 return -EINVAL;
1232
1233 if (camclk->use_count++ == 0) {
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -03001234 clk_set_rate(camclk->clock, si->clk_frequency);
1235 camclk->frequency = si->clk_frequency;
Sylwester Nawrocki3e20c342013-03-21 14:47:17 -03001236 ret = pm_runtime_get_sync(fmd->pmf);
1237 if (ret < 0)
1238 return ret;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001239 ret = clk_enable(camclk->clock);
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -03001240 dbg("Enabled camclk %d: f: %lu", si->clk_id,
Sylwester Nawrockie3fc82e2012-05-17 14:22:10 -03001241 clk_get_rate(camclk->clock));
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001242 }
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001243 return ret;
1244 }
1245
1246 if (WARN_ON(camclk->use_count == 0))
1247 return 0;
1248
1249 if (--camclk->use_count == 0) {
1250 clk_disable(camclk->clock);
Sylwester Nawrocki3e20c342013-03-21 14:47:17 -03001251 pm_runtime_put(fmd->pmf);
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -03001252 dbg("Disabled camclk %d", si->clk_id);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001253 }
1254 return ret;
1255}
1256
1257/**
1258 * fimc_md_set_camclk - peripheral sensor clock setup
1259 * @sd: sensor subdev to configure sclk_cam clock for
1260 * @on: 1 to enable or 0 to disable the clock
1261 *
1262 * There are 2 separate clock outputs available in the SoC for external
1263 * image processors. These clocks are shared between all registered FIMC
1264 * devices to which sensors can be attached, either directly or through
1265 * the MIPI CSI receiver. The clock is allowed here to be used by
1266 * multiple sensors concurrently if they use same frequency.
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001267 * This function should only be called when the graph mutex is held.
1268 */
1269int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
1270{
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -03001271 struct fimc_source_info *si = v4l2_get_subdev_hostdata(sd);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001272 struct fimc_md *fmd = entity_to_fimc_mdev(&sd->entity);
1273
Sylwester Nawrocki4c8f0622013-04-09 11:11:58 -03001274 return __fimc_md_set_camclk(fmd, si, on);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001275}
1276
1277static int fimc_md_link_notify(struct media_pad *source,
1278 struct media_pad *sink, u32 flags)
1279{
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -03001280 struct exynos_video_entity *ve;
1281 struct video_device *vdev;
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -03001282 struct fimc_pipeline *pipeline;
Sylwester Nawrocki8c6ecdd2013-02-05 15:43:08 -03001283 int i, ret = 0;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001284
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -03001285 if (media_entity_type(sink->entity) != MEDIA_ENT_T_DEVNODE_V4L)
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001286 return 0;
1287
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -03001288 vdev = media_entity_to_video_device(sink->entity);
1289 ve = vdev_to_exynos_video_entity(vdev);
1290 pipeline = to_fimc_pipeline(ve->pipe);
Sylwester Nawrocki0f735f52012-04-27 09:33:10 -03001291
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -03001292 if (!(flags & MEDIA_LNK_FL_ENABLED) && pipeline->subdevs[IDX_SENSOR]) {
1293 if (sink->entity->use_count > 0)
1294 ret = __fimc_pipeline_close(ve->pipe);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001295
Sylwester Nawrocki740ad922012-12-06 10:26:19 -03001296 for (i = 0; i < IDX_MAX; i++)
1297 pipeline->subdevs[i] = NULL;
Sylwester Nawrocki42625fd2013-05-31 11:37:20 -03001298 } else if (sink->entity->use_count > 0) {
Sylwester Nawrocki8c6ecdd2013-02-05 15:43:08 -03001299 /*
1300 * Link activation. Enable power of pipeline elements only if
1301 * the pipeline is already in use, i.e. its video node is open.
1302 * Recreate the controls destroyed during the link deactivation.
1303 */
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -03001304 ret = __fimc_pipeline_open(ve->pipe, sink->entity, true);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001305 }
Sylwester Nawrocki740ad922012-12-06 10:26:19 -03001306
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001307 return ret ? -EPIPE : ret;
1308}
1309
1310static ssize_t fimc_md_sysfs_show(struct device *dev,
1311 struct device_attribute *attr, char *buf)
1312{
1313 struct platform_device *pdev = to_platform_device(dev);
1314 struct fimc_md *fmd = platform_get_drvdata(pdev);
1315
1316 if (fmd->user_subdev_api)
1317 return strlcpy(buf, "Sub-device API (sub-dev)\n", PAGE_SIZE);
1318
1319 return strlcpy(buf, "V4L2 video node only API (vid-dev)\n", PAGE_SIZE);
1320}
1321
1322static ssize_t fimc_md_sysfs_store(struct device *dev,
1323 struct device_attribute *attr,
1324 const char *buf, size_t count)
1325{
1326 struct platform_device *pdev = to_platform_device(dev);
1327 struct fimc_md *fmd = platform_get_drvdata(pdev);
1328 bool subdev_api;
1329 int i;
1330
1331 if (!strcmp(buf, "vid-dev\n"))
1332 subdev_api = false;
1333 else if (!strcmp(buf, "sub-dev\n"))
1334 subdev_api = true;
1335 else
1336 return count;
1337
1338 fmd->user_subdev_api = subdev_api;
1339 for (i = 0; i < FIMC_MAX_DEVS; i++)
1340 if (fmd->fimc[i])
1341 fmd->fimc[i]->vid_cap.user_subdev_api = subdev_api;
1342 return count;
1343}
1344/*
1345 * This device attribute is to select video pipeline configuration method.
1346 * There are following valid values:
1347 * vid-dev - for V4L2 video node API only, subdevice will be configured
1348 * by the host driver.
1349 * sub-dev - for media controller API, subdevs must be configured in user
1350 * space before starting streaming.
1351 */
1352static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO,
1353 fimc_md_sysfs_show, fimc_md_sysfs_store);
1354
Sylwester Nawrocki41638512013-03-08 10:41:47 -03001355static int fimc_md_get_pinctrl(struct fimc_md *fmd)
1356{
1357 struct device *dev = &fmd->pdev->dev;
1358 struct fimc_pinctrl *pctl = &fmd->pinctl;
1359
1360 pctl->pinctrl = devm_pinctrl_get(dev);
1361 if (IS_ERR(pctl->pinctrl))
1362 return PTR_ERR(pctl->pinctrl);
1363
1364 pctl->state_default = pinctrl_lookup_state(pctl->pinctrl,
1365 PINCTRL_STATE_DEFAULT);
1366 if (IS_ERR(pctl->state_default))
1367 return PTR_ERR(pctl->state_default);
1368
1369 pctl->state_idle = pinctrl_lookup_state(pctl->pinctrl,
1370 PINCTRL_STATE_IDLE);
1371 return 0;
1372}
1373
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -03001374static int fimc_md_probe(struct platform_device *pdev)
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001375{
Sylwester Nawrockie2985a22013-03-08 12:59:33 -03001376 struct device *dev = &pdev->dev;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001377 struct v4l2_device *v4l2_dev;
1378 struct fimc_md *fmd;
1379 int ret;
1380
Sylwester Nawrockie2985a22013-03-08 12:59:33 -03001381 fmd = devm_kzalloc(dev, sizeof(*fmd), GFP_KERNEL);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001382 if (!fmd)
1383 return -ENOMEM;
1384
1385 spin_lock_init(&fmd->slock);
1386 fmd->pdev = pdev;
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -03001387 INIT_LIST_HEAD(&fmd->pipelines);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001388
1389 strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC",
1390 sizeof(fmd->media_dev.model));
1391 fmd->media_dev.link_notify = fimc_md_link_notify;
Sylwester Nawrockie2985a22013-03-08 12:59:33 -03001392 fmd->media_dev.dev = dev;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001393
1394 v4l2_dev = &fmd->v4l2_dev;
1395 v4l2_dev->mdev = &fmd->media_dev;
Sylwester Nawrockie1d72f42011-06-10 15:36:58 -03001396 v4l2_dev->notify = fimc_sensor_notify;
Sylwester Nawrockie2985a22013-03-08 12:59:33 -03001397 strlcpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name));
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001398
Sylwester Nawrockie781bbe32013-03-21 14:49:16 -03001399 fmd->use_isp = fimc_md_is_isp_available(dev->of_node);
1400
Sylwester Nawrockie2985a22013-03-08 12:59:33 -03001401 ret = v4l2_device_register(dev, &fmd->v4l2_dev);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001402 if (ret < 0) {
1403 v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
Sylwester Nawrocki6d91a512012-01-30 11:37:59 -03001404 return ret;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001405 }
1406 ret = media_device_register(&fmd->media_dev);
1407 if (ret < 0) {
1408 v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret);
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -03001409 goto err_md;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001410 }
1411 ret = fimc_md_get_clocks(fmd);
1412 if (ret)
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -03001413 goto err_clk;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001414
Sylwester Nawrockie2985a22013-03-08 12:59:33 -03001415 fmd->user_subdev_api = (dev->of_node != NULL);
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -03001416
1417 /* Protect the media graph while we're registering entities */
1418 mutex_lock(&fmd->media_dev.graph_mutex);
1419
Sylwester Nawrocki41638512013-03-08 10:41:47 -03001420 ret = fimc_md_get_pinctrl(fmd);
1421 if (ret < 0) {
1422 if (ret != EPROBE_DEFER)
1423 dev_err(dev, "Failed to get pinctrl: %d\n", ret);
1424 goto err_unlock;
1425 }
1426
Sylwester Nawrockie2985a22013-03-08 12:59:33 -03001427 if (dev->of_node)
1428 ret = fimc_md_register_of_platform_entities(fmd, dev->of_node);
1429 else
1430 ret = bus_for_each_dev(&platform_bus_type, NULL, fmd,
1431 fimc_md_pdev_match);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001432 if (ret)
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -03001433 goto err_unlock;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001434
Sylwester Nawrocki2b13f7d2013-03-29 14:12:39 -03001435 if (dev->platform_data || dev->of_node) {
Sylwester Nawrocki5cbf6f162011-10-07 07:40:00 -03001436 ret = fimc_md_register_sensor_entities(fmd);
1437 if (ret)
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -03001438 goto err_unlock;
Sylwester Nawrocki5cbf6f162011-10-07 07:40:00 -03001439 }
Sylwester Nawrockie2985a22013-03-08 12:59:33 -03001440
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001441 ret = fimc_md_create_links(fmd);
1442 if (ret)
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -03001443 goto err_unlock;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001444 ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev);
1445 if (ret)
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -03001446 goto err_unlock;
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001447
1448 ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode);
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -03001449 if (ret)
1450 goto err_unlock;
1451
1452 platform_set_drvdata(pdev, fmd);
1453 mutex_unlock(&fmd->media_dev.graph_mutex);
1454 return 0;
1455
1456err_unlock:
1457 mutex_unlock(&fmd->media_dev.graph_mutex);
1458err_clk:
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001459 media_device_unregister(&fmd->media_dev);
1460 fimc_md_put_clocks(fmd);
1461 fimc_md_unregister_entities(fmd);
Sylwester Nawrocki693f5c42012-04-20 18:57:25 -03001462err_md:
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001463 v4l2_device_unregister(&fmd->v4l2_dev);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001464 return ret;
1465}
1466
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -08001467static int fimc_md_remove(struct platform_device *pdev)
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001468{
1469 struct fimc_md *fmd = platform_get_drvdata(pdev);
1470
1471 if (!fmd)
1472 return 0;
1473 device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
1474 fimc_md_unregister_entities(fmd);
Sylwester Nawrocki403dfbe2013-05-31 11:37:22 -03001475 fimc_md_pipelines_free(fmd);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001476 media_device_unregister(&fmd->media_dev);
1477 fimc_md_put_clocks(fmd);
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001478 return 0;
1479}
1480
Sylwester Nawrockie2985a22013-03-08 12:59:33 -03001481static struct platform_device_id fimc_driver_ids[] __always_unused = {
1482 { .name = "s5p-fimc-md" },
1483 { },
1484};
1485MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
1486
1487static const struct of_device_id fimc_md_of_match[] = {
1488 { .compatible = "samsung,fimc" },
1489 { },
1490};
1491MODULE_DEVICE_TABLE(of, fimc_md_of_match);
1492
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001493static struct platform_driver fimc_md_driver = {
1494 .probe = fimc_md_probe,
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -08001495 .remove = fimc_md_remove,
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001496 .driver = {
Sylwester Nawrockie2985a22013-03-08 12:59:33 -03001497 .of_match_table = of_match_ptr(fimc_md_of_match),
1498 .name = "s5p-fimc-md",
1499 .owner = THIS_MODULE,
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001500 }
1501};
1502
Sachin Kamat7e566be2012-05-26 11:11:54 -03001503static int __init fimc_md_init(void)
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001504{
1505 int ret;
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -03001506
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001507 request_module("s5p-csis");
1508 ret = fimc_register_driver();
1509 if (ret)
1510 return ret;
Sylwester Nawrockiecd9acb2012-03-21 09:58:09 -03001511
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001512 return platform_driver_register(&fimc_md_driver);
1513}
Sachin Kamat7e566be2012-05-26 11:11:54 -03001514
1515static void __exit fimc_md_exit(void)
Sylwester Nawrockid3953222011-09-01 06:01:08 -03001516{
1517 platform_driver_unregister(&fimc_md_driver);
1518 fimc_unregister_driver();
1519}
1520
1521module_init(fimc_md_init);
1522module_exit(fimc_md_exit);
1523
1524MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1525MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver");
1526MODULE_LICENSE("GPL");
1527MODULE_VERSION("2.0.1");