1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Rockchip MIPI CSI2 Driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2019 Rockchip Electronics Co., Ltd.
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/clk.h>
9*4882a593Smuzhiyun #include <linux/interrupt.h>
10*4882a593Smuzhiyun #include <linux/io.h>
11*4882a593Smuzhiyun #include <linux/iopoll.h>
12*4882a593Smuzhiyun #include <linux/irq.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/of.h>
15*4882a593Smuzhiyun #include <linux/of_graph.h>
16*4882a593Smuzhiyun #include <linux/of_platform.h>
17*4882a593Smuzhiyun #include <linux/platform_device.h>
18*4882a593Smuzhiyun #include <linux/reset.h>
19*4882a593Smuzhiyun #include <linux/rk-camera-module.h>
20*4882a593Smuzhiyun #include <media/v4l2-ioctl.h>
21*4882a593Smuzhiyun #include "mipi-csi2.h"
22*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun static int csi2_debug;
25*4882a593Smuzhiyun module_param_named(debug_csi2, csi2_debug, int, 0644);
26*4882a593Smuzhiyun MODULE_PARM_DESC(debug_csi2, "Debug level (0-1)");
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #define write_csihost_reg(base, addr, val) writel(val, (addr) + (base))
29*4882a593Smuzhiyun #define read_csihost_reg(base, addr) readl((addr) + (base))
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun static ATOMIC_NOTIFIER_HEAD(g_csi_host_chain);
32*4882a593Smuzhiyun
rkcif_csi2_register_notifier(struct notifier_block * nb)33*4882a593Smuzhiyun int rkcif_csi2_register_notifier(struct notifier_block *nb)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun return atomic_notifier_chain_register(&g_csi_host_chain, nb);
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun
rkcif_csi2_unregister_notifier(struct notifier_block * nb)38*4882a593Smuzhiyun int rkcif_csi2_unregister_notifier(struct notifier_block *nb)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun return atomic_notifier_chain_unregister(&g_csi_host_chain, nb);
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun
sd_to_dev(struct v4l2_subdev * sdev)43*4882a593Smuzhiyun static inline struct csi2_dev *sd_to_dev(struct v4l2_subdev *sdev)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun return container_of(sdev, struct csi2_dev, sd);
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun
sd_to_sensor(struct csi2_dev * csi2,struct v4l2_subdev * sd)48*4882a593Smuzhiyun static struct csi2_sensor_info *sd_to_sensor(struct csi2_dev *csi2,
49*4882a593Smuzhiyun struct v4l2_subdev *sd)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun int i;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun for (i = 0; i < csi2->num_sensors; ++i)
54*4882a593Smuzhiyun if (csi2->sensors[i].sd == sd)
55*4882a593Smuzhiyun return &csi2->sensors[i];
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun return NULL;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
get_remote_sensor(struct v4l2_subdev * sd)60*4882a593Smuzhiyun static struct v4l2_subdev *get_remote_sensor(struct v4l2_subdev *sd)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun struct media_pad *local, *remote;
63*4882a593Smuzhiyun struct media_entity *sensor_me;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun local = &sd->entity.pads[RK_CSI2_PAD_SINK];
66*4882a593Smuzhiyun remote = media_entity_remote_pad(local);
67*4882a593Smuzhiyun if (!remote) {
68*4882a593Smuzhiyun v4l2_warn(sd, "No link between dphy and sensor\n");
69*4882a593Smuzhiyun return NULL;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun sensor_me = media_entity_remote_pad(local)->entity;
73*4882a593Smuzhiyun return media_entity_to_v4l2_subdev(sensor_me);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
get_remote_terminal_sensor(struct v4l2_subdev * sd,struct v4l2_subdev ** sensor_sd)76*4882a593Smuzhiyun static void get_remote_terminal_sensor(struct v4l2_subdev *sd,
77*4882a593Smuzhiyun struct v4l2_subdev **sensor_sd)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun struct media_graph graph;
80*4882a593Smuzhiyun struct media_entity *entity = &sd->entity;
81*4882a593Smuzhiyun struct media_device *mdev = entity->graph_obj.mdev;
82*4882a593Smuzhiyun int ret;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun /* Walk the graph to locate sensor nodes. */
85*4882a593Smuzhiyun mutex_lock(&mdev->graph_mutex);
86*4882a593Smuzhiyun ret = media_graph_walk_init(&graph, mdev);
87*4882a593Smuzhiyun if (ret) {
88*4882a593Smuzhiyun mutex_unlock(&mdev->graph_mutex);
89*4882a593Smuzhiyun *sensor_sd = NULL;
90*4882a593Smuzhiyun return;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun media_graph_walk_start(&graph, entity);
94*4882a593Smuzhiyun while ((entity = media_graph_walk_next(&graph))) {
95*4882a593Smuzhiyun if (entity->function == MEDIA_ENT_F_CAM_SENSOR)
96*4882a593Smuzhiyun break;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun mutex_unlock(&mdev->graph_mutex);
99*4882a593Smuzhiyun media_graph_walk_cleanup(&graph);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun if (entity)
102*4882a593Smuzhiyun *sensor_sd = media_entity_to_v4l2_subdev(entity);
103*4882a593Smuzhiyun else
104*4882a593Smuzhiyun *sensor_sd = NULL;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
csi2_update_sensor_info(struct csi2_dev * csi2)107*4882a593Smuzhiyun static void csi2_update_sensor_info(struct csi2_dev *csi2)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun struct v4l2_subdev *terminal_sensor_sd = NULL;
110*4882a593Smuzhiyun struct csi2_sensor_info *sensor = &csi2->sensors[0];
111*4882a593Smuzhiyun struct v4l2_mbus_config mbus;
112*4882a593Smuzhiyun int ret = 0;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun ret = v4l2_subdev_call(sensor->sd, pad, get_mbus_config, 0, &mbus);
115*4882a593Smuzhiyun if (ret) {
116*4882a593Smuzhiyun v4l2_err(&csi2->sd, "update sensor info failed!\n");
117*4882a593Smuzhiyun return;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun get_remote_terminal_sensor(&csi2->sd, &terminal_sensor_sd);
121*4882a593Smuzhiyun ret = v4l2_subdev_call(terminal_sensor_sd, core, ioctl,
122*4882a593Smuzhiyun RKMODULE_GET_CSI_DSI_INFO, &csi2->dsi_input_en);
123*4882a593Smuzhiyun if (ret) {
124*4882a593Smuzhiyun v4l2_dbg(1, csi2_debug, &csi2->sd, "get CSI/DSI sel failed, default csi!\n");
125*4882a593Smuzhiyun csi2->dsi_input_en = 0;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun csi2->bus.flags = mbus.flags;
129*4882a593Smuzhiyun switch (csi2->bus.flags & V4L2_MBUS_CSI2_LANES) {
130*4882a593Smuzhiyun case V4L2_MBUS_CSI2_1_LANE:
131*4882a593Smuzhiyun csi2->bus.num_data_lanes = 1;
132*4882a593Smuzhiyun break;
133*4882a593Smuzhiyun case V4L2_MBUS_CSI2_2_LANE:
134*4882a593Smuzhiyun csi2->bus.num_data_lanes = 2;
135*4882a593Smuzhiyun break;
136*4882a593Smuzhiyun case V4L2_MBUS_CSI2_3_LANE:
137*4882a593Smuzhiyun csi2->bus.num_data_lanes = 3;
138*4882a593Smuzhiyun break;
139*4882a593Smuzhiyun case V4L2_MBUS_CSI2_4_LANE:
140*4882a593Smuzhiyun csi2->bus.num_data_lanes = 4;
141*4882a593Smuzhiyun break;
142*4882a593Smuzhiyun default:
143*4882a593Smuzhiyun v4l2_warn(&csi2->sd, "lane num is invalid\n");
144*4882a593Smuzhiyun csi2->bus.num_data_lanes = 0;
145*4882a593Smuzhiyun break;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
csi2_hw_do_reset(struct csi2_hw * csi2_hw)150*4882a593Smuzhiyun static void csi2_hw_do_reset(struct csi2_hw *csi2_hw)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun if (!csi2_hw->rsts_bulk)
154*4882a593Smuzhiyun return;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun reset_control_assert(csi2_hw->rsts_bulk);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun udelay(5);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun reset_control_deassert(csi2_hw->rsts_bulk);
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
csi2_enable_clks(struct csi2_hw * csi2_hw)163*4882a593Smuzhiyun static int csi2_enable_clks(struct csi2_hw *csi2_hw)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun int ret = 0;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun if (!csi2_hw->clks_bulk)
168*4882a593Smuzhiyun return -EINVAL;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun ret = clk_bulk_prepare_enable(csi2_hw->clks_num, csi2_hw->clks_bulk);
171*4882a593Smuzhiyun if (ret)
172*4882a593Smuzhiyun dev_err(csi2_hw->dev, "failed to enable clks\n");
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun return ret;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
csi2_disable_clks(struct csi2_hw * csi2_hw)177*4882a593Smuzhiyun static void csi2_disable_clks(struct csi2_hw *csi2_hw)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun if (!csi2_hw->clks_bulk)
180*4882a593Smuzhiyun return;
181*4882a593Smuzhiyun clk_bulk_disable_unprepare(csi2_hw->clks_num, csi2_hw->clks_bulk);
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
csi2_disable(struct csi2_hw * csi2_hw)184*4882a593Smuzhiyun static void csi2_disable(struct csi2_hw *csi2_hw)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun write_csihost_reg(csi2_hw->base, CSIHOST_RESETN, 0);
187*4882a593Smuzhiyun write_csihost_reg(csi2_hw->base, CSIHOST_MSK1, 0xffffffff);
188*4882a593Smuzhiyun write_csihost_reg(csi2_hw->base, CSIHOST_MSK2, 0xffffffff);
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun static int csi2_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
192*4882a593Smuzhiyun struct v4l2_mbus_config *mbus);
193*4882a593Smuzhiyun
csi2_enable(struct csi2_hw * csi2_hw,enum host_type_t host_type)194*4882a593Smuzhiyun static void csi2_enable(struct csi2_hw *csi2_hw,
195*4882a593Smuzhiyun enum host_type_t host_type)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun void __iomem *base = csi2_hw->base;
198*4882a593Smuzhiyun struct csi2_dev *csi2 = csi2_hw->csi2;
199*4882a593Smuzhiyun int lanes = csi2->bus.num_data_lanes;
200*4882a593Smuzhiyun struct v4l2_mbus_config mbus;
201*4882a593Smuzhiyun u32 val = 0;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun csi2_g_mbus_config(&csi2->sd, 0, &mbus);
204*4882a593Smuzhiyun if (mbus.type == V4L2_MBUS_CSI2_DPHY)
205*4882a593Smuzhiyun val = SW_CPHY_EN(0);
206*4882a593Smuzhiyun else if (mbus.type == V4L2_MBUS_CSI2_CPHY)
207*4882a593Smuzhiyun val = SW_CPHY_EN(1);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun write_csihost_reg(base, CSIHOST_N_LANES, lanes - 1);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (host_type == RK_DSI_RXHOST) {
212*4882a593Smuzhiyun val |= SW_DSI_EN(1) | SW_DATATYPE_FS(0x01) |
213*4882a593Smuzhiyun SW_DATATYPE_FE(0x11) | SW_DATATYPE_LS(0x21) |
214*4882a593Smuzhiyun SW_DATATYPE_LE(0x31);
215*4882a593Smuzhiyun write_csihost_reg(base, CSIHOST_CONTROL, val);
216*4882a593Smuzhiyun /* Disable some error interrupt when HOST work on DSI RX mode */
217*4882a593Smuzhiyun write_csihost_reg(base, CSIHOST_MSK1, 0xe00000f0);
218*4882a593Smuzhiyun write_csihost_reg(base, CSIHOST_MSK2, 0xff00);
219*4882a593Smuzhiyun } else {
220*4882a593Smuzhiyun val |= SW_DSI_EN(0) | SW_DATATYPE_FS(0x0) |
221*4882a593Smuzhiyun SW_DATATYPE_FE(0x01) | SW_DATATYPE_LS(0x02) |
222*4882a593Smuzhiyun SW_DATATYPE_LE(0x03);
223*4882a593Smuzhiyun write_csihost_reg(base, CSIHOST_CONTROL, val);
224*4882a593Smuzhiyun write_csihost_reg(base, CSIHOST_MSK1, 0x0);
225*4882a593Smuzhiyun write_csihost_reg(base, CSIHOST_MSK2, 0xf000);
226*4882a593Smuzhiyun csi2->is_check_sot_sync = true;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun write_csihost_reg(base, CSIHOST_RESETN, 1);
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
csi2_start(struct csi2_dev * csi2)232*4882a593Smuzhiyun static int csi2_start(struct csi2_dev *csi2)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun enum host_type_t host_type;
235*4882a593Smuzhiyun int ret, i;
236*4882a593Smuzhiyun int csi_idx = 0;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun atomic_set(&csi2->frm_sync_seq, 0);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun csi2_update_sensor_info(csi2);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun if (csi2->dsi_input_en == RKMODULE_DSI_INPUT)
243*4882a593Smuzhiyun host_type = RK_DSI_RXHOST;
244*4882a593Smuzhiyun else
245*4882a593Smuzhiyun host_type = RK_CSI_RXHOST;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun for (i = 0; i < csi2->csi_info.csi_num; i++) {
248*4882a593Smuzhiyun csi_idx = csi2->csi_info.csi_idx[i];
249*4882a593Smuzhiyun csi2_hw_do_reset(csi2->csi2_hw[csi_idx]);
250*4882a593Smuzhiyun ret = csi2_enable_clks(csi2->csi2_hw[csi_idx]);
251*4882a593Smuzhiyun if (ret) {
252*4882a593Smuzhiyun v4l2_err(&csi2->sd, "%s: enable clks failed\n", __func__);
253*4882a593Smuzhiyun return ret;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun csi2_enable(csi2->csi2_hw[csi_idx], host_type);
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun pr_debug("stream sd: %s\n", csi2->src_sd->name);
259*4882a593Smuzhiyun ret = v4l2_subdev_call(csi2->src_sd, video, s_stream, 1);
260*4882a593Smuzhiyun ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
261*4882a593Smuzhiyun if (ret)
262*4882a593Smuzhiyun goto err_assert_reset;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun for (i = 0; i < RK_CSI2_ERR_MAX; i++)
265*4882a593Smuzhiyun csi2->err_list[i].cnt = 0;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun return 0;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun err_assert_reset:
270*4882a593Smuzhiyun for (i = 0; i < csi2->csi_info.csi_num; i++) {
271*4882a593Smuzhiyun csi_idx = csi2->csi_info.csi_idx[i];
272*4882a593Smuzhiyun csi2_disable(csi2->csi2_hw[csi_idx]);
273*4882a593Smuzhiyun csi2_disable_clks(csi2->csi2_hw[csi_idx]);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun return ret;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
csi2_stop(struct csi2_dev * csi2)279*4882a593Smuzhiyun static void csi2_stop(struct csi2_dev *csi2)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun int i = 0;
282*4882a593Smuzhiyun int csi_idx = 0;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /* stop upstream */
285*4882a593Smuzhiyun v4l2_subdev_call(csi2->src_sd, video, s_stream, 0);
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun for (i = 0; i < csi2->csi_info.csi_num; i++) {
288*4882a593Smuzhiyun csi_idx = csi2->csi_info.csi_idx[i];
289*4882a593Smuzhiyun csi2_disable(csi2->csi2_hw[csi_idx]);
290*4882a593Smuzhiyun csi2_hw_do_reset(csi2->csi2_hw[csi_idx]);
291*4882a593Smuzhiyun csi2_disable_clks(csi2->csi2_hw[csi_idx]);
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun /*
296*4882a593Smuzhiyun * V4L2 subdev operations.
297*4882a593Smuzhiyun */
298*4882a593Smuzhiyun
csi2_s_stream(struct v4l2_subdev * sd,int enable)299*4882a593Smuzhiyun static int csi2_s_stream(struct v4l2_subdev *sd, int enable)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun struct csi2_dev *csi2 = sd_to_dev(sd);
302*4882a593Smuzhiyun int ret = 0;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun mutex_lock(&csi2->lock);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun dev_err(csi2->dev, "stream %s, src_sd: %p, sd_name:%s\n",
307*4882a593Smuzhiyun enable ? "on" : "off",
308*4882a593Smuzhiyun csi2->src_sd, csi2->src_sd->name);
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun /*
311*4882a593Smuzhiyun * enable/disable streaming only if stream_count is
312*4882a593Smuzhiyun * going from 0 to 1 / 1 to 0.
313*4882a593Smuzhiyun */
314*4882a593Smuzhiyun if (csi2->stream_count != !enable)
315*4882a593Smuzhiyun goto update_count;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun dev_err(csi2->dev, "stream %s\n", enable ? "ON" : "OFF");
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (enable)
320*4882a593Smuzhiyun ret = csi2_start(csi2);
321*4882a593Smuzhiyun else
322*4882a593Smuzhiyun csi2_stop(csi2);
323*4882a593Smuzhiyun if (ret)
324*4882a593Smuzhiyun goto out;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun update_count:
327*4882a593Smuzhiyun csi2->stream_count += enable ? 1 : -1;
328*4882a593Smuzhiyun if (csi2->stream_count < 0)
329*4882a593Smuzhiyun csi2->stream_count = 0;
330*4882a593Smuzhiyun out:
331*4882a593Smuzhiyun mutex_unlock(&csi2->lock);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun return ret;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun
csi2_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)336*4882a593Smuzhiyun static int csi2_link_setup(struct media_entity *entity,
337*4882a593Smuzhiyun const struct media_pad *local,
338*4882a593Smuzhiyun const struct media_pad *remote, u32 flags)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
341*4882a593Smuzhiyun struct csi2_dev *csi2 = sd_to_dev(sd);
342*4882a593Smuzhiyun struct v4l2_subdev *remote_sd;
343*4882a593Smuzhiyun int ret = 0;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun remote_sd = media_entity_to_v4l2_subdev(remote->entity);
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun mutex_lock(&csi2->lock);
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun if (local->flags & MEDIA_PAD_FL_SOURCE) {
350*4882a593Smuzhiyun if (flags & MEDIA_LNK_FL_ENABLED) {
351*4882a593Smuzhiyun if (csi2->sink_linked[local->index - 1]) {
352*4882a593Smuzhiyun ret = -EBUSY;
353*4882a593Smuzhiyun goto out;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun csi2->sink_linked[local->index - 1] = true;
356*4882a593Smuzhiyun } else {
357*4882a593Smuzhiyun csi2->sink_linked[local->index - 1] = false;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun } else {
360*4882a593Smuzhiyun if (flags & MEDIA_LNK_FL_ENABLED) {
361*4882a593Smuzhiyun if (csi2->src_sd) {
362*4882a593Smuzhiyun ret = -EBUSY;
363*4882a593Smuzhiyun goto out;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun csi2->src_sd = remote_sd;
366*4882a593Smuzhiyun } else {
367*4882a593Smuzhiyun csi2->src_sd = NULL;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun out:
372*4882a593Smuzhiyun mutex_unlock(&csi2->lock);
373*4882a593Smuzhiyun return ret;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
csi2_media_init(struct v4l2_subdev * sd)376*4882a593Smuzhiyun static int csi2_media_init(struct v4l2_subdev *sd)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun struct csi2_dev *csi2 = sd_to_dev(sd);
379*4882a593Smuzhiyun int i = 0, num_pads = 0;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun num_pads = csi2->match_data->num_pads;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun for (i = 0; i < num_pads; i++) {
384*4882a593Smuzhiyun csi2->pad[i].flags = (i == CSI2_SINK_PAD) ?
385*4882a593Smuzhiyun MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun csi2->pad[RK_CSI2X_PAD_SOURCE0].flags =
389*4882a593Smuzhiyun MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
390*4882a593Smuzhiyun csi2->pad[RK_CSI2_PAD_SINK].flags =
391*4882a593Smuzhiyun MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun /* set a default mbus format */
394*4882a593Smuzhiyun csi2->format_mbus.code = MEDIA_BUS_FMT_UYVY8_2X8;
395*4882a593Smuzhiyun csi2->format_mbus.field = V4L2_FIELD_NONE;
396*4882a593Smuzhiyun csi2->format_mbus.width = RKCIF_DEFAULT_WIDTH;
397*4882a593Smuzhiyun csi2->format_mbus.height = RKCIF_DEFAULT_HEIGHT;
398*4882a593Smuzhiyun csi2->crop.top = 0;
399*4882a593Smuzhiyun csi2->crop.left = 0;
400*4882a593Smuzhiyun csi2->crop.width = RKCIF_DEFAULT_WIDTH;
401*4882a593Smuzhiyun csi2->crop.height = RKCIF_DEFAULT_HEIGHT;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun return media_entity_pads_init(&sd->entity, num_pads, csi2->pad);
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun /* csi2 accepts all fmt/size from sensor */
csi2_get_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)407*4882a593Smuzhiyun static int csi2_get_set_fmt(struct v4l2_subdev *sd,
408*4882a593Smuzhiyun struct v4l2_subdev_pad_config *cfg,
409*4882a593Smuzhiyun struct v4l2_subdev_format *fmt)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun int ret;
412*4882a593Smuzhiyun struct csi2_dev *csi2 = sd_to_dev(sd);
413*4882a593Smuzhiyun struct v4l2_subdev *sensor = get_remote_sensor(sd);
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun /*
416*4882a593Smuzhiyun * Do not allow format changes and just relay whatever
417*4882a593Smuzhiyun * set currently in the sensor.
418*4882a593Smuzhiyun */
419*4882a593Smuzhiyun ret = v4l2_subdev_call(sensor, pad, get_fmt, NULL, fmt);
420*4882a593Smuzhiyun if (!ret)
421*4882a593Smuzhiyun csi2->format_mbus = fmt->format;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun return ret;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
mipi_csi2_get_crop(struct csi2_dev * csi2,struct v4l2_subdev_pad_config * cfg,enum v4l2_subdev_format_whence which)426*4882a593Smuzhiyun static struct v4l2_rect *mipi_csi2_get_crop(struct csi2_dev *csi2,
427*4882a593Smuzhiyun struct v4l2_subdev_pad_config *cfg,
428*4882a593Smuzhiyun enum v4l2_subdev_format_whence which)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun if (which == V4L2_SUBDEV_FORMAT_TRY)
431*4882a593Smuzhiyun return v4l2_subdev_get_try_crop(&csi2->sd, cfg, RK_CSI2_PAD_SINK);
432*4882a593Smuzhiyun else
433*4882a593Smuzhiyun return &csi2->crop;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
csi2_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_selection * sel)436*4882a593Smuzhiyun static int csi2_get_selection(struct v4l2_subdev *sd,
437*4882a593Smuzhiyun struct v4l2_subdev_pad_config *cfg,
438*4882a593Smuzhiyun struct v4l2_subdev_selection *sel)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun struct csi2_dev *csi2 = sd_to_dev(sd);
441*4882a593Smuzhiyun struct v4l2_subdev *sensor = get_remote_sensor(sd);
442*4882a593Smuzhiyun struct v4l2_subdev_format fmt;
443*4882a593Smuzhiyun int ret = 0;
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun if (!sel) {
446*4882a593Smuzhiyun v4l2_dbg(1, csi2_debug, &csi2->sd, "sel is null\n");
447*4882a593Smuzhiyun goto err;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun if (sel->pad > RK_CSI2X_PAD_SOURCE3) {
451*4882a593Smuzhiyun v4l2_dbg(1, csi2_debug, &csi2->sd, "pad[%d] isn't matched\n", sel->pad);
452*4882a593Smuzhiyun goto err;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun switch (sel->target) {
456*4882a593Smuzhiyun case V4L2_SEL_TGT_CROP_BOUNDS:
457*4882a593Smuzhiyun if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
458*4882a593Smuzhiyun sel->pad = 0;
459*4882a593Smuzhiyun ret = v4l2_subdev_call(sensor, pad, get_selection,
460*4882a593Smuzhiyun cfg, sel);
461*4882a593Smuzhiyun if (ret) {
462*4882a593Smuzhiyun fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
463*4882a593Smuzhiyun fmt.pad = 0;
464*4882a593Smuzhiyun ret = v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt);
465*4882a593Smuzhiyun if (!ret) {
466*4882a593Smuzhiyun csi2->format_mbus = fmt.format;
467*4882a593Smuzhiyun sel->r.top = 0;
468*4882a593Smuzhiyun sel->r.left = 0;
469*4882a593Smuzhiyun sel->r.width = csi2->format_mbus.width;
470*4882a593Smuzhiyun sel->r.height = csi2->format_mbus.height;
471*4882a593Smuzhiyun csi2->crop = sel->r;
472*4882a593Smuzhiyun } else {
473*4882a593Smuzhiyun sel->r = csi2->crop;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun } else {
476*4882a593Smuzhiyun csi2->crop = sel->r;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun } else {
479*4882a593Smuzhiyun sel->r = *v4l2_subdev_get_try_crop(&csi2->sd, cfg, sel->pad);
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun break;
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun case V4L2_SEL_TGT_CROP:
484*4882a593Smuzhiyun sel->r = *mipi_csi2_get_crop(csi2, cfg, sel->which);
485*4882a593Smuzhiyun break;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun default:
488*4882a593Smuzhiyun return -EINVAL;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun return 0;
492*4882a593Smuzhiyun err:
493*4882a593Smuzhiyun return -EINVAL;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun
csi2_set_selection(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_selection * sel)496*4882a593Smuzhiyun static int csi2_set_selection(struct v4l2_subdev *sd,
497*4882a593Smuzhiyun struct v4l2_subdev_pad_config *cfg,
498*4882a593Smuzhiyun struct v4l2_subdev_selection *sel)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun struct csi2_dev *csi2 = sd_to_dev(sd);
501*4882a593Smuzhiyun struct v4l2_subdev *sensor = get_remote_sensor(sd);
502*4882a593Smuzhiyun int ret = 0;
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun ret = v4l2_subdev_call(sensor, pad, set_selection,
505*4882a593Smuzhiyun cfg, sel);
506*4882a593Smuzhiyun if (!ret)
507*4882a593Smuzhiyun csi2->crop = sel->r;
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun return ret;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun
csi2_g_mbus_config(struct v4l2_subdev * sd,unsigned int pad_id,struct v4l2_mbus_config * mbus)512*4882a593Smuzhiyun static int csi2_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
513*4882a593Smuzhiyun struct v4l2_mbus_config *mbus)
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun struct csi2_dev *csi2 = sd_to_dev(sd);
516*4882a593Smuzhiyun struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
517*4882a593Smuzhiyun int ret;
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun ret = v4l2_subdev_call(sensor_sd, pad, get_mbus_config, 0, mbus);
520*4882a593Smuzhiyun if (ret) {
521*4882a593Smuzhiyun mbus->type = V4L2_MBUS_CSI2_DPHY;
522*4882a593Smuzhiyun mbus->flags = csi2->bus.flags;
523*4882a593Smuzhiyun mbus->flags |= BIT(csi2->bus.num_data_lanes - 1);
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun return 0;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun static const struct media_entity_operations csi2_entity_ops = {
530*4882a593Smuzhiyun .link_setup = csi2_link_setup,
531*4882a593Smuzhiyun .link_validate = v4l2_subdev_link_validate,
532*4882a593Smuzhiyun };
533*4882a593Smuzhiyun
rkcif_csi2_event_reset_pipe(struct csi2_dev * csi2_dev,int reset_src)534*4882a593Smuzhiyun void rkcif_csi2_event_reset_pipe(struct csi2_dev *csi2_dev, int reset_src)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun if (csi2_dev) {
537*4882a593Smuzhiyun struct v4l2_event event = {
538*4882a593Smuzhiyun .type = V4L2_EVENT_RESET_DEV,
539*4882a593Smuzhiyun .reserved[0] = reset_src,
540*4882a593Smuzhiyun };
541*4882a593Smuzhiyun v4l2_event_queue(csi2_dev->sd.devnode, &event);
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
rkcif_csi2_event_inc_sof(struct csi2_dev * csi2_dev)545*4882a593Smuzhiyun void rkcif_csi2_event_inc_sof(struct csi2_dev *csi2_dev)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun if (csi2_dev) {
548*4882a593Smuzhiyun struct v4l2_event event = {
549*4882a593Smuzhiyun .type = V4L2_EVENT_FRAME_SYNC,
550*4882a593Smuzhiyun .u.frame_sync.frame_sequence =
551*4882a593Smuzhiyun atomic_inc_return(&csi2_dev->frm_sync_seq) - 1,
552*4882a593Smuzhiyun };
553*4882a593Smuzhiyun v4l2_event_queue(csi2_dev->sd.devnode, &event);
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
rkcif_csi2_get_sof(struct csi2_dev * csi2_dev)557*4882a593Smuzhiyun u32 rkcif_csi2_get_sof(struct csi2_dev *csi2_dev)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun if (csi2_dev)
560*4882a593Smuzhiyun return atomic_read(&csi2_dev->frm_sync_seq) - 1;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun return 0;
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun
rkcif_csi2_set_sof(struct csi2_dev * csi2_dev,u32 seq)565*4882a593Smuzhiyun void rkcif_csi2_set_sof(struct csi2_dev *csi2_dev, u32 seq)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun if (csi2_dev)
568*4882a593Smuzhiyun atomic_set(&csi2_dev->frm_sync_seq, seq);
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun
rkcif_csi2_subscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)571*4882a593Smuzhiyun static int rkcif_csi2_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
572*4882a593Smuzhiyun struct v4l2_event_subscription *sub)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun if (sub->type == V4L2_EVENT_FRAME_SYNC ||
575*4882a593Smuzhiyun sub->type == V4L2_EVENT_RESET_DEV)
576*4882a593Smuzhiyun return v4l2_event_subscribe(fh, sub, RKCIF_V4L2_EVENT_ELEMS, NULL);
577*4882a593Smuzhiyun else
578*4882a593Smuzhiyun return -EINVAL;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun
rkcif_csi2_s_power(struct v4l2_subdev * sd,int on)581*4882a593Smuzhiyun static int rkcif_csi2_s_power(struct v4l2_subdev *sd, int on)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun return 0;
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun
rkcif_csi2_ioctl(struct v4l2_subdev * sd,unsigned int cmd,void * arg)586*4882a593Smuzhiyun static long rkcif_csi2_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun struct csi2_dev *csi2 = sd_to_dev(sd);
589*4882a593Smuzhiyun struct v4l2_subdev *sensor = get_remote_sensor(sd);
590*4882a593Smuzhiyun long ret = 0;
591*4882a593Smuzhiyun int i = 0;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun switch (cmd) {
594*4882a593Smuzhiyun case RKCIF_CMD_SET_CSI_IDX:
595*4882a593Smuzhiyun csi2->csi_info = *((struct rkcif_csi_info *)arg);
596*4882a593Smuzhiyun for (i = 0; i < csi2->csi_info.csi_num; i++)
597*4882a593Smuzhiyun csi2->csi2_hw[csi2->csi_info.csi_idx[i]]->csi2 = csi2;
598*4882a593Smuzhiyun if (csi2->match_data->chip_id > CHIP_RV1126_CSI2)
599*4882a593Smuzhiyun ret = v4l2_subdev_call(sensor, core, ioctl,
600*4882a593Smuzhiyun RKCIF_CMD_SET_CSI_IDX,
601*4882a593Smuzhiyun arg);
602*4882a593Smuzhiyun break;
603*4882a593Smuzhiyun default:
604*4882a593Smuzhiyun ret = -ENOIOCTLCMD;
605*4882a593Smuzhiyun break;
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun return ret;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
rkcif_csi2_compat_ioctl32(struct v4l2_subdev * sd,unsigned int cmd,unsigned long arg)612*4882a593Smuzhiyun static long rkcif_csi2_compat_ioctl32(struct v4l2_subdev *sd,
613*4882a593Smuzhiyun unsigned int cmd, unsigned long arg)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun void __user *up = compat_ptr(arg);
616*4882a593Smuzhiyun struct rkcif_csi_info csi_info;
617*4882a593Smuzhiyun long ret;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun switch (cmd) {
620*4882a593Smuzhiyun case RKCIF_CMD_SET_CSI_IDX:
621*4882a593Smuzhiyun if (copy_from_user(&csi_info, up, sizeof(struct rkcif_csi_info)))
622*4882a593Smuzhiyun return -EFAULT;
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun ret = rkcif_csi2_ioctl(sd, cmd, &csi_info);
625*4882a593Smuzhiyun break;
626*4882a593Smuzhiyun default:
627*4882a593Smuzhiyun ret = -ENOIOCTLCMD;
628*4882a593Smuzhiyun break;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun return ret;
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun #endif
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun static const struct v4l2_subdev_core_ops csi2_core_ops = {
636*4882a593Smuzhiyun .subscribe_event = rkcif_csi2_subscribe_event,
637*4882a593Smuzhiyun .unsubscribe_event = v4l2_event_subdev_unsubscribe,
638*4882a593Smuzhiyun .s_power = rkcif_csi2_s_power,
639*4882a593Smuzhiyun .ioctl = rkcif_csi2_ioctl,
640*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
641*4882a593Smuzhiyun .compat_ioctl32 = rkcif_csi2_compat_ioctl32,
642*4882a593Smuzhiyun #endif
643*4882a593Smuzhiyun };
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun static const struct v4l2_subdev_video_ops csi2_video_ops = {
646*4882a593Smuzhiyun .s_stream = csi2_s_stream,
647*4882a593Smuzhiyun };
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
650*4882a593Smuzhiyun .get_fmt = csi2_get_set_fmt,
651*4882a593Smuzhiyun .set_fmt = csi2_get_set_fmt,
652*4882a593Smuzhiyun .get_selection = csi2_get_selection,
653*4882a593Smuzhiyun .set_selection = csi2_set_selection,
654*4882a593Smuzhiyun .get_mbus_config = csi2_g_mbus_config,
655*4882a593Smuzhiyun };
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun static const struct v4l2_subdev_ops csi2_subdev_ops = {
658*4882a593Smuzhiyun .core = &csi2_core_ops,
659*4882a593Smuzhiyun .video = &csi2_video_ops,
660*4882a593Smuzhiyun .pad = &csi2_pad_ops,
661*4882a593Smuzhiyun };
662*4882a593Smuzhiyun
csi2_parse_endpoint(struct device * dev,struct v4l2_fwnode_endpoint * vep,struct v4l2_async_subdev * asd)663*4882a593Smuzhiyun static int csi2_parse_endpoint(struct device *dev,
664*4882a593Smuzhiyun struct v4l2_fwnode_endpoint *vep,
665*4882a593Smuzhiyun struct v4l2_async_subdev *asd)
666*4882a593Smuzhiyun {
667*4882a593Smuzhiyun struct v4l2_subdev *sd = dev_get_drvdata(dev);
668*4882a593Smuzhiyun struct csi2_dev *csi2 = sd_to_dev(sd);
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun if (vep->base.port != 0) {
671*4882a593Smuzhiyun dev_err(dev, "The csi host node needs to parse port 0\n");
672*4882a593Smuzhiyun return -EINVAL;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun csi2->bus = vep->bus.mipi_csi2;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun return 0;
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun /* The .bound() notifier callback when a match is found */
681*4882a593Smuzhiyun static int
csi2_notifier_bound(struct v4l2_async_notifier * notifier,struct v4l2_subdev * sd,struct v4l2_async_subdev * asd)682*4882a593Smuzhiyun csi2_notifier_bound(struct v4l2_async_notifier *notifier,
683*4882a593Smuzhiyun struct v4l2_subdev *sd,
684*4882a593Smuzhiyun struct v4l2_async_subdev *asd)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun struct csi2_dev *csi2 = container_of(notifier,
687*4882a593Smuzhiyun struct csi2_dev,
688*4882a593Smuzhiyun notifier);
689*4882a593Smuzhiyun struct csi2_sensor_info *sensor;
690*4882a593Smuzhiyun struct media_link *link;
691*4882a593Smuzhiyun unsigned int pad, ret;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun if (csi2->num_sensors == ARRAY_SIZE(csi2->sensors)) {
694*4882a593Smuzhiyun v4l2_err(&csi2->sd,
695*4882a593Smuzhiyun "%s: the num of sd is beyond:%d\n",
696*4882a593Smuzhiyun __func__, csi2->num_sensors);
697*4882a593Smuzhiyun return -EBUSY;
698*4882a593Smuzhiyun }
699*4882a593Smuzhiyun sensor = &csi2->sensors[csi2->num_sensors++];
700*4882a593Smuzhiyun sensor->sd = sd;
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun for (pad = 0; pad < sd->entity.num_pads; pad++)
703*4882a593Smuzhiyun if (sensor->sd->entity.pads[pad].flags
704*4882a593Smuzhiyun & MEDIA_PAD_FL_SOURCE)
705*4882a593Smuzhiyun break;
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun if (pad == sensor->sd->entity.num_pads) {
708*4882a593Smuzhiyun dev_err(csi2->dev,
709*4882a593Smuzhiyun "failed to find src pad for %s\n",
710*4882a593Smuzhiyun sd->name);
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun return -ENXIO;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun ret = media_create_pad_link(&sensor->sd->entity, pad,
716*4882a593Smuzhiyun &csi2->sd.entity, RK_CSI2_PAD_SINK,
717*4882a593Smuzhiyun 0/* csi2->num_sensors != 1 ? 0 : MEDIA_LNK_FL_ENABLED */);
718*4882a593Smuzhiyun if (ret) {
719*4882a593Smuzhiyun dev_err(csi2->dev,
720*4882a593Smuzhiyun "failed to create link for %s\n",
721*4882a593Smuzhiyun sd->name);
722*4882a593Smuzhiyun return ret;
723*4882a593Smuzhiyun }
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun link = list_first_entry(&csi2->sd.entity.links, struct media_link, list);
726*4882a593Smuzhiyun ret = media_entity_setup_link(link, MEDIA_LNK_FL_ENABLED);
727*4882a593Smuzhiyun if (ret) {
728*4882a593Smuzhiyun dev_err(csi2->dev,
729*4882a593Smuzhiyun "failed to create link for %s\n",
730*4882a593Smuzhiyun sensor->sd->name);
731*4882a593Smuzhiyun return ret;
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun return 0;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun /* The .unbind callback */
csi2_notifier_unbind(struct v4l2_async_notifier * notifier,struct v4l2_subdev * sd,struct v4l2_async_subdev * asd)738*4882a593Smuzhiyun static void csi2_notifier_unbind(struct v4l2_async_notifier *notifier,
739*4882a593Smuzhiyun struct v4l2_subdev *sd,
740*4882a593Smuzhiyun struct v4l2_async_subdev *asd)
741*4882a593Smuzhiyun {
742*4882a593Smuzhiyun struct csi2_dev *csi2 = container_of(notifier,
743*4882a593Smuzhiyun struct csi2_dev,
744*4882a593Smuzhiyun notifier);
745*4882a593Smuzhiyun struct csi2_sensor_info *sensor = sd_to_sensor(csi2, sd);
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun if (sensor)
748*4882a593Smuzhiyun sensor->sd = NULL;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun static const struct
752*4882a593Smuzhiyun v4l2_async_notifier_operations csi2_async_ops = {
753*4882a593Smuzhiyun .bound = csi2_notifier_bound,
754*4882a593Smuzhiyun .unbind = csi2_notifier_unbind,
755*4882a593Smuzhiyun };
756*4882a593Smuzhiyun
csi2_find_err_vc(int val,char * vc_info)757*4882a593Smuzhiyun static void csi2_find_err_vc(int val, char *vc_info)
758*4882a593Smuzhiyun {
759*4882a593Smuzhiyun int i;
760*4882a593Smuzhiyun char cur_str[CSI_VCINFO_LEN] = {0};
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun memset(vc_info, 0, sizeof(*vc_info));
763*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
764*4882a593Smuzhiyun if ((val >> i) & 0x1) {
765*4882a593Smuzhiyun snprintf(cur_str, CSI_VCINFO_LEN, " %d", i);
766*4882a593Smuzhiyun if (strlen(vc_info) + strlen(cur_str) < CSI_VCINFO_LEN)
767*4882a593Smuzhiyun strncat(vc_info, cur_str, strlen(cur_str));
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun }
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun #define csi2_err_strncat(dst_str, src_str) {\
773*4882a593Smuzhiyun if (strlen(dst_str) + strlen(src_str) < CSI_ERRSTR_LEN)\
774*4882a593Smuzhiyun strncat(dst_str, src_str, strlen(src_str)); }
775*4882a593Smuzhiyun
rk_csirx_irq1_handler(int irq,void * ctx)776*4882a593Smuzhiyun static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx)
777*4882a593Smuzhiyun {
778*4882a593Smuzhiyun struct device *dev = ctx;
779*4882a593Smuzhiyun struct csi2_hw *csi2_hw = dev_get_drvdata(dev);
780*4882a593Smuzhiyun struct csi2_dev *csi2 = csi2_hw->csi2;
781*4882a593Smuzhiyun struct csi2_err_stats *err_list = NULL;
782*4882a593Smuzhiyun unsigned long err_stat = 0;
783*4882a593Smuzhiyun u32 val;
784*4882a593Smuzhiyun char err_str[CSI_ERRSTR_LEN] = {0};
785*4882a593Smuzhiyun char cur_str[CSI_ERRSTR_LEN] = {0};
786*4882a593Smuzhiyun char vc_info[CSI_VCINFO_LEN] = {0};
787*4882a593Smuzhiyun bool is_add_cnt = false;
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun val = read_csihost_reg(csi2_hw->base, CSIHOST_ERR1);
790*4882a593Smuzhiyun if (val) {
791*4882a593Smuzhiyun if (val & CSIHOST_ERR1_PHYERR_SPTSYNCHS) {
792*4882a593Smuzhiyun err_list = &csi2->err_list[RK_CSI2_ERR_SOTSYN];
793*4882a593Smuzhiyun err_list->cnt++;
794*4882a593Smuzhiyun if (csi2->match_data->chip_id == CHIP_RK3588_CSI2) {
795*4882a593Smuzhiyun if (err_list->cnt > 3 &&
796*4882a593Smuzhiyun csi2->err_list[RK_CSI2_ERR_ALL].cnt <= err_list->cnt) {
797*4882a593Smuzhiyun csi2->is_check_sot_sync = false;
798*4882a593Smuzhiyun write_csihost_reg(csi2_hw->base, CSIHOST_MSK1, 0xf);
799*4882a593Smuzhiyun }
800*4882a593Smuzhiyun if (csi2->is_check_sot_sync) {
801*4882a593Smuzhiyun csi2_find_err_vc(val & 0xf, vc_info);
802*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(sot sync,lane:%s) ", vc_info);
803*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun } else {
806*4882a593Smuzhiyun csi2_find_err_vc(val & 0xf, vc_info);
807*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(sot sync,lane:%s) ", vc_info);
808*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
809*4882a593Smuzhiyun is_add_cnt = true;
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun if (val & CSIHOST_ERR1_ERR_BNDRY_MATCH) {
814*4882a593Smuzhiyun err_list = &csi2->err_list[RK_CSI2_ERR_FS_FE_MIS];
815*4882a593Smuzhiyun err_list->cnt++;
816*4882a593Smuzhiyun csi2_find_err_vc((val >> 4) & 0xf, vc_info);
817*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(fs/fe mis,vc:%s) ", vc_info);
818*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
819*4882a593Smuzhiyun if (csi2->match_data->chip_id < CHIP_RK3588_CSI2)
820*4882a593Smuzhiyun is_add_cnt = true;
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun if (val & CSIHOST_ERR1_ERR_SEQ) {
824*4882a593Smuzhiyun err_list = &csi2->err_list[RK_CSI2_ERR_FRM_SEQ_ERR];
825*4882a593Smuzhiyun err_list->cnt++;
826*4882a593Smuzhiyun csi2_find_err_vc((val >> 8) & 0xf, vc_info);
827*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(f_seq,vc:%s) ", vc_info);
828*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun if (val & CSIHOST_ERR1_ERR_FRM_DATA) {
832*4882a593Smuzhiyun err_list = &csi2->err_list[RK_CSI2_ERR_CRC_ONCE];
833*4882a593Smuzhiyun is_add_cnt = true;
834*4882a593Smuzhiyun err_list->cnt++;
835*4882a593Smuzhiyun csi2_find_err_vc((val >> 12) & 0xf, vc_info);
836*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(err_data,vc:%s) ", vc_info);
837*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun if (val & CSIHOST_ERR1_ERR_CRC) {
841*4882a593Smuzhiyun err_list = &csi2->err_list[RK_CSI2_ERR_CRC];
842*4882a593Smuzhiyun err_list->cnt++;
843*4882a593Smuzhiyun is_add_cnt = true;
844*4882a593Smuzhiyun csi2_find_err_vc((val >> 24) & 0xf, vc_info);
845*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(crc,vc:%s) ", vc_info);
846*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun if (val & CSIHOST_ERR1_ERR_ECC2) {
850*4882a593Smuzhiyun err_list = &csi2->err_list[RK_CSI2_ERR_CRC];
851*4882a593Smuzhiyun err_list->cnt++;
852*4882a593Smuzhiyun is_add_cnt = true;
853*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc2) ");
854*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun if (val & CSIHOST_ERR1_ERR_CTRL) {
858*4882a593Smuzhiyun csi2_find_err_vc((val >> 16) & 0xf, vc_info);
859*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(ctrl,vc:%s) ", vc_info);
860*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
861*4882a593Smuzhiyun }
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun pr_err("%s ERR1:0x%x %s\n", csi2_hw->dev_name, val, err_str);
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun if (is_add_cnt) {
866*4882a593Smuzhiyun csi2->err_list[RK_CSI2_ERR_ALL].cnt++;
867*4882a593Smuzhiyun err_stat = ((csi2->err_list[RK_CSI2_ERR_FS_FE_MIS].cnt & 0xff) << 8) |
868*4882a593Smuzhiyun ((csi2->err_list[RK_CSI2_ERR_ALL].cnt) & 0xff);
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun atomic_notifier_call_chain(&g_csi_host_chain,
871*4882a593Smuzhiyun err_stat,
872*4882a593Smuzhiyun &csi2->csi_info.csi_idx[csi2->csi_info.csi_num - 1]);
873*4882a593Smuzhiyun }
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun return IRQ_HANDLED;
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun
rk_csirx_irq2_handler(int irq,void * ctx)880*4882a593Smuzhiyun static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx)
881*4882a593Smuzhiyun {
882*4882a593Smuzhiyun struct device *dev = ctx;
883*4882a593Smuzhiyun struct csi2_hw *csi2_hw = dev_get_drvdata(dev);
884*4882a593Smuzhiyun u32 val;
885*4882a593Smuzhiyun char cur_str[CSI_ERRSTR_LEN] = {0};
886*4882a593Smuzhiyun char err_str[CSI_ERRSTR_LEN] = {0};
887*4882a593Smuzhiyun char vc_info[CSI_VCINFO_LEN] = {0};
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun val = read_csihost_reg(csi2_hw->base, CSIHOST_ERR2);
890*4882a593Smuzhiyun if (val) {
891*4882a593Smuzhiyun if (val & CSIHOST_ERR2_PHYERR_ESC) {
892*4882a593Smuzhiyun csi2_find_err_vc(val & 0xf, vc_info);
893*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(ULPM,lane:%s) ", vc_info);
894*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun if (val & CSIHOST_ERR2_PHYERR_SOTHS) {
897*4882a593Smuzhiyun csi2_find_err_vc((val >> 4) & 0xf, vc_info);
898*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(sot,lane:%s) ", vc_info);
899*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun if (val & CSIHOST_ERR2_ECC_CORRECTED) {
902*4882a593Smuzhiyun csi2_find_err_vc((val >> 8) & 0xf, vc_info);
903*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc,vc:%s) ", vc_info);
904*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
905*4882a593Smuzhiyun }
906*4882a593Smuzhiyun if (val & CSIHOST_ERR2_ERR_ID) {
907*4882a593Smuzhiyun csi2_find_err_vc((val >> 12) & 0xf, vc_info);
908*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(err id,vc:%s) ", vc_info);
909*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
910*4882a593Smuzhiyun }
911*4882a593Smuzhiyun if (val & CSIHOST_ERR2_PHYERR_CODEHS) {
912*4882a593Smuzhiyun snprintf(cur_str, CSI_ERRSTR_LEN, "(err code) ");
913*4882a593Smuzhiyun csi2_err_strncat(err_str, cur_str);
914*4882a593Smuzhiyun }
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun pr_err("%s ERR2:0x%x %s\n", csi2_hw->dev_name, val, err_str);
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun return IRQ_HANDLED;
920*4882a593Smuzhiyun }
921*4882a593Smuzhiyun
csi2_notifier(struct csi2_dev * csi2)922*4882a593Smuzhiyun static int csi2_notifier(struct csi2_dev *csi2)
923*4882a593Smuzhiyun {
924*4882a593Smuzhiyun struct v4l2_async_notifier *ntf = &csi2->notifier;
925*4882a593Smuzhiyun int ret;
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun v4l2_async_notifier_init(ntf);
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(csi2->dev,
930*4882a593Smuzhiyun &csi2->notifier,
931*4882a593Smuzhiyun sizeof(struct v4l2_async_subdev), 0,
932*4882a593Smuzhiyun csi2_parse_endpoint);
933*4882a593Smuzhiyun if (ret < 0)
934*4882a593Smuzhiyun return ret;
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun csi2->sd.subdev_notifier = &csi2->notifier;
937*4882a593Smuzhiyun csi2->notifier.ops = &csi2_async_ops;
938*4882a593Smuzhiyun ret = v4l2_async_subdev_notifier_register(&csi2->sd, &csi2->notifier);
939*4882a593Smuzhiyun if (ret) {
940*4882a593Smuzhiyun v4l2_err(&csi2->sd,
941*4882a593Smuzhiyun "failed to register async notifier : %d\n",
942*4882a593Smuzhiyun ret);
943*4882a593Smuzhiyun v4l2_async_notifier_cleanup(&csi2->notifier);
944*4882a593Smuzhiyun return ret;
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun ret = v4l2_async_register_subdev(&csi2->sd);
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun return ret;
950*4882a593Smuzhiyun }
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun static const struct csi2_match_data rk1808_csi2_match_data = {
953*4882a593Smuzhiyun .chip_id = CHIP_RK1808_CSI2,
954*4882a593Smuzhiyun .num_pads = CSI2_NUM_PADS,
955*4882a593Smuzhiyun .num_hw = 1,
956*4882a593Smuzhiyun };
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun static const struct csi2_match_data rk3288_csi2_match_data = {
959*4882a593Smuzhiyun .chip_id = CHIP_RK3288_CSI2,
960*4882a593Smuzhiyun .num_pads = CSI2_NUM_PADS_SINGLE_LINK,
961*4882a593Smuzhiyun .num_hw = 1,
962*4882a593Smuzhiyun };
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun static const struct csi2_match_data rv1126_csi2_match_data = {
965*4882a593Smuzhiyun .chip_id = CHIP_RV1126_CSI2,
966*4882a593Smuzhiyun .num_pads = CSI2_NUM_PADS,
967*4882a593Smuzhiyun .num_hw = 1,
968*4882a593Smuzhiyun };
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun static const struct csi2_match_data rk3568_csi2_match_data = {
971*4882a593Smuzhiyun .chip_id = CHIP_RK3568_CSI2,
972*4882a593Smuzhiyun .num_pads = CSI2_NUM_PADS,
973*4882a593Smuzhiyun .num_hw = 1,
974*4882a593Smuzhiyun };
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun static const struct csi2_match_data rk3588_csi2_match_data = {
977*4882a593Smuzhiyun .chip_id = CHIP_RK3588_CSI2,
978*4882a593Smuzhiyun .num_pads = CSI2_NUM_PADS_MAX,
979*4882a593Smuzhiyun .num_hw = 6,
980*4882a593Smuzhiyun };
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun static const struct csi2_match_data rv1106_csi2_match_data = {
983*4882a593Smuzhiyun .chip_id = CHIP_RV1106_CSI2,
984*4882a593Smuzhiyun .num_pads = CSI2_NUM_PADS_MAX,
985*4882a593Smuzhiyun .num_hw = 2,
986*4882a593Smuzhiyun };
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun static const struct csi2_match_data rk3562_csi2_match_data = {
989*4882a593Smuzhiyun .chip_id = CHIP_RK3562_CSI2,
990*4882a593Smuzhiyun .num_pads = CSI2_NUM_PADS_MAX,
991*4882a593Smuzhiyun .num_hw = 4,
992*4882a593Smuzhiyun };
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun static const struct of_device_id csi2_dt_ids[] = {
995*4882a593Smuzhiyun {
996*4882a593Smuzhiyun .compatible = "rockchip,rk1808-mipi-csi2",
997*4882a593Smuzhiyun .data = &rk1808_csi2_match_data,
998*4882a593Smuzhiyun },
999*4882a593Smuzhiyun {
1000*4882a593Smuzhiyun .compatible = "rockchip,rk3288-mipi-csi2",
1001*4882a593Smuzhiyun .data = &rk3288_csi2_match_data,
1002*4882a593Smuzhiyun },
1003*4882a593Smuzhiyun {
1004*4882a593Smuzhiyun .compatible = "rockchip,rk3568-mipi-csi2",
1005*4882a593Smuzhiyun .data = &rk3568_csi2_match_data,
1006*4882a593Smuzhiyun },
1007*4882a593Smuzhiyun {
1008*4882a593Smuzhiyun .compatible = "rockchip,rv1126-mipi-csi2",
1009*4882a593Smuzhiyun .data = &rv1126_csi2_match_data,
1010*4882a593Smuzhiyun },
1011*4882a593Smuzhiyun {
1012*4882a593Smuzhiyun .compatible = "rockchip,rk3588-mipi-csi2",
1013*4882a593Smuzhiyun .data = &rk3588_csi2_match_data,
1014*4882a593Smuzhiyun },
1015*4882a593Smuzhiyun {
1016*4882a593Smuzhiyun .compatible = "rockchip,rv1106-mipi-csi2",
1017*4882a593Smuzhiyun .data = &rv1106_csi2_match_data,
1018*4882a593Smuzhiyun },
1019*4882a593Smuzhiyun {
1020*4882a593Smuzhiyun .compatible = "rockchip,rk3562-mipi-csi2",
1021*4882a593Smuzhiyun .data = &rk3562_csi2_match_data,
1022*4882a593Smuzhiyun },
1023*4882a593Smuzhiyun { /* sentinel */ }
1024*4882a593Smuzhiyun };
1025*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, csi2_dt_ids);
1026*4882a593Smuzhiyun
csi2_attach_hw(struct csi2_dev * csi2)1027*4882a593Smuzhiyun static int csi2_attach_hw(struct csi2_dev *csi2)
1028*4882a593Smuzhiyun {
1029*4882a593Smuzhiyun struct device_node *np;
1030*4882a593Smuzhiyun struct platform_device *pdev;
1031*4882a593Smuzhiyun struct csi2_hw *hw;
1032*4882a593Smuzhiyun int i = 0;
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun for (i = 0; i < csi2->match_data->num_hw; i++) {
1035*4882a593Smuzhiyun np = of_parse_phandle(csi2->dev->of_node, "rockchip,hw", i);
1036*4882a593Smuzhiyun if (!np || !of_device_is_available(np)) {
1037*4882a593Smuzhiyun dev_err(csi2->dev, "failed to get csi2 hw node\n");
1038*4882a593Smuzhiyun return -ENODEV;
1039*4882a593Smuzhiyun }
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun pdev = of_find_device_by_node(np);
1042*4882a593Smuzhiyun of_node_put(np);
1043*4882a593Smuzhiyun if (!pdev) {
1044*4882a593Smuzhiyun dev_err(csi2->dev, "failed to get csi2 hw from node\n");
1045*4882a593Smuzhiyun return -ENODEV;
1046*4882a593Smuzhiyun }
1047*4882a593Smuzhiyun
1048*4882a593Smuzhiyun hw = platform_get_drvdata(pdev);
1049*4882a593Smuzhiyun if (!hw) {
1050*4882a593Smuzhiyun dev_err(csi2->dev, "failed attach csi2 hw\n");
1051*4882a593Smuzhiyun return -EINVAL;
1052*4882a593Smuzhiyun }
1053*4882a593Smuzhiyun
1054*4882a593Smuzhiyun hw->csi2 = csi2;
1055*4882a593Smuzhiyun csi2->csi2_hw[i] = hw;
1056*4882a593Smuzhiyun }
1057*4882a593Smuzhiyun dev_info(csi2->dev, "attach to csi2 hw node\n");
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun return 0;
1060*4882a593Smuzhiyun }
1061*4882a593Smuzhiyun
csi2_probe(struct platform_device * pdev)1062*4882a593Smuzhiyun static int csi2_probe(struct platform_device *pdev)
1063*4882a593Smuzhiyun {
1064*4882a593Smuzhiyun const struct of_device_id *match;
1065*4882a593Smuzhiyun struct device_node *node = pdev->dev.of_node;
1066*4882a593Smuzhiyun struct csi2_dev *csi2 = NULL;
1067*4882a593Smuzhiyun const struct csi2_match_data *data;
1068*4882a593Smuzhiyun int ret;
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun match = of_match_node(csi2_dt_ids, node);
1071*4882a593Smuzhiyun if (IS_ERR(match))
1072*4882a593Smuzhiyun return PTR_ERR(match);
1073*4882a593Smuzhiyun data = match->data;
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun csi2 = devm_kzalloc(&pdev->dev, sizeof(*csi2), GFP_KERNEL);
1076*4882a593Smuzhiyun if (!csi2)
1077*4882a593Smuzhiyun return -ENOMEM;
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun csi2->dev = &pdev->dev;
1080*4882a593Smuzhiyun csi2->match_data = data;
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun csi2->dev_name = node->name;
1083*4882a593Smuzhiyun v4l2_subdev_init(&csi2->sd, &csi2_subdev_ops);
1084*4882a593Smuzhiyun v4l2_set_subdevdata(&csi2->sd, &pdev->dev);
1085*4882a593Smuzhiyun csi2->sd.entity.ops = &csi2_entity_ops;
1086*4882a593Smuzhiyun csi2->sd.dev = &pdev->dev;
1087*4882a593Smuzhiyun csi2->sd.owner = THIS_MODULE;
1088*4882a593Smuzhiyun csi2->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
1089*4882a593Smuzhiyun ret = strscpy(csi2->sd.name, DEVICE_NAME, sizeof(csi2->sd.name));
1090*4882a593Smuzhiyun if (ret < 0)
1091*4882a593Smuzhiyun v4l2_err(&csi2->sd, "failed to copy name\n");
1092*4882a593Smuzhiyun platform_set_drvdata(pdev, &csi2->sd);
1093*4882a593Smuzhiyun
1094*4882a593Smuzhiyun ret = csi2_attach_hw(csi2);
1095*4882a593Smuzhiyun if (ret) {
1096*4882a593Smuzhiyun v4l2_err(&csi2->sd, "must enable all mipi csi2 hw node\n");
1097*4882a593Smuzhiyun return -EINVAL;
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun mutex_init(&csi2->lock);
1100*4882a593Smuzhiyun
1101*4882a593Smuzhiyun ret = csi2_media_init(&csi2->sd);
1102*4882a593Smuzhiyun if (ret < 0)
1103*4882a593Smuzhiyun goto rmmutex;
1104*4882a593Smuzhiyun ret = csi2_notifier(csi2);
1105*4882a593Smuzhiyun if (ret)
1106*4882a593Smuzhiyun goto rmmutex;
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun v4l2_info(&csi2->sd, "probe success, v4l2_dev:%s!\n", csi2->sd.v4l2_dev->name);
1109*4882a593Smuzhiyun
1110*4882a593Smuzhiyun return 0;
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun rmmutex:
1113*4882a593Smuzhiyun mutex_destroy(&csi2->lock);
1114*4882a593Smuzhiyun return ret;
1115*4882a593Smuzhiyun }
1116*4882a593Smuzhiyun
csi2_remove(struct platform_device * pdev)1117*4882a593Smuzhiyun static int csi2_remove(struct platform_device *pdev)
1118*4882a593Smuzhiyun {
1119*4882a593Smuzhiyun struct v4l2_subdev *sd = platform_get_drvdata(pdev);
1120*4882a593Smuzhiyun struct csi2_dev *csi2 = sd_to_dev(sd);
1121*4882a593Smuzhiyun
1122*4882a593Smuzhiyun v4l2_async_unregister_subdev(sd);
1123*4882a593Smuzhiyun mutex_destroy(&csi2->lock);
1124*4882a593Smuzhiyun media_entity_cleanup(&sd->entity);
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun return 0;
1127*4882a593Smuzhiyun }
1128*4882a593Smuzhiyun
1129*4882a593Smuzhiyun static struct platform_driver csi2_driver = {
1130*4882a593Smuzhiyun .driver = {
1131*4882a593Smuzhiyun .name = DEVICE_NAME,
1132*4882a593Smuzhiyun .of_match_table = csi2_dt_ids,
1133*4882a593Smuzhiyun },
1134*4882a593Smuzhiyun .probe = csi2_probe,
1135*4882a593Smuzhiyun .remove = csi2_remove,
1136*4882a593Smuzhiyun };
1137*4882a593Smuzhiyun
rkcif_csi2_plat_drv_init(void)1138*4882a593Smuzhiyun int rkcif_csi2_plat_drv_init(void)
1139*4882a593Smuzhiyun {
1140*4882a593Smuzhiyun return platform_driver_register(&csi2_driver);
1141*4882a593Smuzhiyun }
1142*4882a593Smuzhiyun
rkcif_csi2_plat_drv_exit(void)1143*4882a593Smuzhiyun void rkcif_csi2_plat_drv_exit(void)
1144*4882a593Smuzhiyun {
1145*4882a593Smuzhiyun platform_driver_unregister(&csi2_driver);
1146*4882a593Smuzhiyun }
1147*4882a593Smuzhiyun
1148*4882a593Smuzhiyun static const struct csi2_hw_match_data rk1808_csi2_hw_match_data = {
1149*4882a593Smuzhiyun .chip_id = CHIP_RK1808_CSI2,
1150*4882a593Smuzhiyun };
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun static const struct csi2_hw_match_data rk3288_csi2_hw_match_data = {
1153*4882a593Smuzhiyun .chip_id = CHIP_RK3288_CSI2,
1154*4882a593Smuzhiyun };
1155*4882a593Smuzhiyun
1156*4882a593Smuzhiyun static const struct csi2_hw_match_data rv1126_csi2_hw_match_data = {
1157*4882a593Smuzhiyun .chip_id = CHIP_RV1126_CSI2,
1158*4882a593Smuzhiyun };
1159*4882a593Smuzhiyun
1160*4882a593Smuzhiyun static const struct csi2_hw_match_data rk3568_csi2_hw_match_data = {
1161*4882a593Smuzhiyun .chip_id = CHIP_RK3568_CSI2,
1162*4882a593Smuzhiyun };
1163*4882a593Smuzhiyun
1164*4882a593Smuzhiyun static const struct csi2_hw_match_data rk3588_csi2_hw_match_data = {
1165*4882a593Smuzhiyun .chip_id = CHIP_RK3588_CSI2,
1166*4882a593Smuzhiyun };
1167*4882a593Smuzhiyun
1168*4882a593Smuzhiyun static const struct csi2_hw_match_data rv1106_csi2_hw_match_data = {
1169*4882a593Smuzhiyun .chip_id = CHIP_RV1106_CSI2,
1170*4882a593Smuzhiyun };
1171*4882a593Smuzhiyun
1172*4882a593Smuzhiyun static const struct csi2_hw_match_data rk3562_csi2_hw_match_data = {
1173*4882a593Smuzhiyun .chip_id = CHIP_RK3562_CSI2,
1174*4882a593Smuzhiyun };
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun static const struct of_device_id csi2_hw_ids[] = {
1177*4882a593Smuzhiyun {
1178*4882a593Smuzhiyun .compatible = "rockchip,rk1808-mipi-csi2-hw",
1179*4882a593Smuzhiyun .data = &rk1808_csi2_hw_match_data,
1180*4882a593Smuzhiyun },
1181*4882a593Smuzhiyun {
1182*4882a593Smuzhiyun .compatible = "rockchip,rk3288-mipi-csi2-hw",
1183*4882a593Smuzhiyun .data = &rk3288_csi2_hw_match_data,
1184*4882a593Smuzhiyun },
1185*4882a593Smuzhiyun {
1186*4882a593Smuzhiyun .compatible = "rockchip,rk3568-mipi-csi2-hw",
1187*4882a593Smuzhiyun .data = &rk3568_csi2_hw_match_data,
1188*4882a593Smuzhiyun },
1189*4882a593Smuzhiyun {
1190*4882a593Smuzhiyun .compatible = "rockchip,rv1126-mipi-csi2-hw",
1191*4882a593Smuzhiyun .data = &rv1126_csi2_hw_match_data,
1192*4882a593Smuzhiyun },
1193*4882a593Smuzhiyun {
1194*4882a593Smuzhiyun .compatible = "rockchip,rk3588-mipi-csi2-hw",
1195*4882a593Smuzhiyun .data = &rk3588_csi2_hw_match_data,
1196*4882a593Smuzhiyun },
1197*4882a593Smuzhiyun {
1198*4882a593Smuzhiyun .compatible = "rockchip,rv1106-mipi-csi2-hw",
1199*4882a593Smuzhiyun .data = &rv1106_csi2_hw_match_data,
1200*4882a593Smuzhiyun },
1201*4882a593Smuzhiyun {
1202*4882a593Smuzhiyun .compatible = "rockchip,rk3562-mipi-csi2-hw",
1203*4882a593Smuzhiyun .data = &rk3588_csi2_hw_match_data,
1204*4882a593Smuzhiyun },
1205*4882a593Smuzhiyun { /* sentinel */ }
1206*4882a593Smuzhiyun };
1207*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, csi2_hw_ids);
1208*4882a593Smuzhiyun
csi2_hw_probe(struct platform_device * pdev)1209*4882a593Smuzhiyun static int csi2_hw_probe(struct platform_device *pdev)
1210*4882a593Smuzhiyun {
1211*4882a593Smuzhiyun const struct of_device_id *match;
1212*4882a593Smuzhiyun struct device *dev = &pdev->dev;
1213*4882a593Smuzhiyun struct device_node *node = pdev->dev.of_node;
1214*4882a593Smuzhiyun struct csi2_hw *csi2_hw = NULL;
1215*4882a593Smuzhiyun struct resource *res;
1216*4882a593Smuzhiyun const struct csi2_hw_match_data *data;
1217*4882a593Smuzhiyun int ret, irq;
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun dev_info(&pdev->dev, "enter mipi csi2 hw probe!\n");
1220*4882a593Smuzhiyun match = of_match_node(csi2_hw_ids, node);
1221*4882a593Smuzhiyun if (IS_ERR(match))
1222*4882a593Smuzhiyun return PTR_ERR(match);
1223*4882a593Smuzhiyun data = match->data;
1224*4882a593Smuzhiyun
1225*4882a593Smuzhiyun csi2_hw = devm_kzalloc(&pdev->dev, sizeof(*csi2_hw), GFP_KERNEL);
1226*4882a593Smuzhiyun if (!csi2_hw)
1227*4882a593Smuzhiyun return -ENOMEM;
1228*4882a593Smuzhiyun
1229*4882a593Smuzhiyun csi2_hw->dev = &pdev->dev;
1230*4882a593Smuzhiyun csi2_hw->match_data = data;
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun csi2_hw->dev_name = node->name;
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun csi2_hw->clks_num = devm_clk_bulk_get_all(dev, &csi2_hw->clks_bulk);
1235*4882a593Smuzhiyun if (csi2_hw->clks_num < 0) {
1236*4882a593Smuzhiyun csi2_hw->clks_num = 0;
1237*4882a593Smuzhiyun dev_err(dev, "failed to get csi2 clks\n");
1238*4882a593Smuzhiyun }
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun csi2_hw->rsts_bulk = devm_reset_control_array_get_optional_exclusive(dev);
1241*4882a593Smuzhiyun if (IS_ERR(csi2_hw->rsts_bulk)) {
1242*4882a593Smuzhiyun if (PTR_ERR(csi2_hw->rsts_bulk) != -EPROBE_DEFER)
1243*4882a593Smuzhiyun dev_err(dev, "failed to get csi2 reset\n");
1244*4882a593Smuzhiyun csi2_hw->rsts_bulk = NULL;
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun
1247*4882a593Smuzhiyun res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1248*4882a593Smuzhiyun csi2_hw->base = devm_ioremap_resource(&pdev->dev, res);
1249*4882a593Smuzhiyun if (IS_ERR(csi2_hw->base)) {
1250*4882a593Smuzhiyun resource_size_t offset = res->start;
1251*4882a593Smuzhiyun resource_size_t size = resource_size(res);
1252*4882a593Smuzhiyun
1253*4882a593Smuzhiyun dev_warn(&pdev->dev, "avoid secondary mipi resource check!\n");
1254*4882a593Smuzhiyun
1255*4882a593Smuzhiyun csi2_hw->base = devm_ioremap(&pdev->dev, offset, size);
1256*4882a593Smuzhiyun if (IS_ERR(csi2_hw->base)) {
1257*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to ioremap resource\n");
1258*4882a593Smuzhiyun
1259*4882a593Smuzhiyun return PTR_ERR(csi2_hw->base);
1260*4882a593Smuzhiyun }
1261*4882a593Smuzhiyun }
1262*4882a593Smuzhiyun
1263*4882a593Smuzhiyun irq = platform_get_irq_byname(pdev, "csi-intr1");
1264*4882a593Smuzhiyun if (irq > 0) {
1265*4882a593Smuzhiyun ret = devm_request_irq(&pdev->dev, irq,
1266*4882a593Smuzhiyun rk_csirx_irq1_handler, 0,
1267*4882a593Smuzhiyun dev_driver_string(&pdev->dev),
1268*4882a593Smuzhiyun &pdev->dev);
1269*4882a593Smuzhiyun if (ret < 0)
1270*4882a593Smuzhiyun dev_err(&pdev->dev, "request csi-intr1 irq failed: %d\n",
1271*4882a593Smuzhiyun ret);
1272*4882a593Smuzhiyun csi2_hw->irq1 = irq;
1273*4882a593Smuzhiyun } else {
1274*4882a593Smuzhiyun dev_err(&pdev->dev, "No found irq csi-intr1\n");
1275*4882a593Smuzhiyun }
1276*4882a593Smuzhiyun
1277*4882a593Smuzhiyun irq = platform_get_irq_byname(pdev, "csi-intr2");
1278*4882a593Smuzhiyun if (irq > 0) {
1279*4882a593Smuzhiyun ret = devm_request_irq(&pdev->dev, irq,
1280*4882a593Smuzhiyun rk_csirx_irq2_handler, 0,
1281*4882a593Smuzhiyun dev_driver_string(&pdev->dev),
1282*4882a593Smuzhiyun &pdev->dev);
1283*4882a593Smuzhiyun if (ret < 0)
1284*4882a593Smuzhiyun dev_err(&pdev->dev, "request csi-intr2 failed: %d\n",
1285*4882a593Smuzhiyun ret);
1286*4882a593Smuzhiyun csi2_hw->irq2 = irq;
1287*4882a593Smuzhiyun } else {
1288*4882a593Smuzhiyun dev_err(&pdev->dev, "No found irq csi-intr2\n");
1289*4882a593Smuzhiyun }
1290*4882a593Smuzhiyun platform_set_drvdata(pdev, csi2_hw);
1291*4882a593Smuzhiyun dev_info(&pdev->dev, "probe success, v4l2_dev:%s!\n", csi2_hw->dev_name);
1292*4882a593Smuzhiyun
1293*4882a593Smuzhiyun return 0;
1294*4882a593Smuzhiyun }
1295*4882a593Smuzhiyun
csi2_hw_remove(struct platform_device * pdev)1296*4882a593Smuzhiyun static int csi2_hw_remove(struct platform_device *pdev)
1297*4882a593Smuzhiyun {
1298*4882a593Smuzhiyun return 0;
1299*4882a593Smuzhiyun }
1300*4882a593Smuzhiyun
1301*4882a593Smuzhiyun static struct platform_driver csi2_hw_driver = {
1302*4882a593Smuzhiyun .driver = {
1303*4882a593Smuzhiyun .name = DEVICE_NAME_HW,
1304*4882a593Smuzhiyun .of_match_table = csi2_hw_ids,
1305*4882a593Smuzhiyun },
1306*4882a593Smuzhiyun .probe = csi2_hw_probe,
1307*4882a593Smuzhiyun .remove = csi2_hw_remove,
1308*4882a593Smuzhiyun };
1309*4882a593Smuzhiyun
rkcif_csi2_hw_plat_drv_init(void)1310*4882a593Smuzhiyun int rkcif_csi2_hw_plat_drv_init(void)
1311*4882a593Smuzhiyun {
1312*4882a593Smuzhiyun return platform_driver_register(&csi2_hw_driver);
1313*4882a593Smuzhiyun }
1314*4882a593Smuzhiyun
rkcif_csi2_hw_plat_drv_exit(void)1315*4882a593Smuzhiyun void rkcif_csi2_hw_plat_drv_exit(void)
1316*4882a593Smuzhiyun {
1317*4882a593Smuzhiyun platform_driver_unregister(&csi2_hw_driver);
1318*4882a593Smuzhiyun }
1319*4882a593Smuzhiyun
1320*4882a593Smuzhiyun MODULE_DESCRIPTION("Rockchip MIPI CSI2 driver");
1321*4882a593Smuzhiyun MODULE_AUTHOR("Macrofly.xu <xuhf@rock-chips.com>");
1322*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1323