xref: /OK3568_Linux_fs/kernel/drivers/media/platform/exynos4-is/fimc-is.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
8*4882a593Smuzhiyun  *          Younghwan Joo <yhwan.joo@samsung.com>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun #define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/device.h>
13*4882a593Smuzhiyun #include <linux/debugfs.h>
14*4882a593Smuzhiyun #include <linux/delay.h>
15*4882a593Smuzhiyun #include <linux/errno.h>
16*4882a593Smuzhiyun #include <linux/firmware.h>
17*4882a593Smuzhiyun #include <linux/interrupt.h>
18*4882a593Smuzhiyun #include <linux/kernel.h>
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/i2c.h>
21*4882a593Smuzhiyun #include <linux/of_irq.h>
22*4882a593Smuzhiyun #include <linux/of_address.h>
23*4882a593Smuzhiyun #include <linux/of_graph.h>
24*4882a593Smuzhiyun #include <linux/of_platform.h>
25*4882a593Smuzhiyun #include <linux/platform_device.h>
26*4882a593Smuzhiyun #include <linux/pm_runtime.h>
27*4882a593Smuzhiyun #include <linux/slab.h>
28*4882a593Smuzhiyun #include <linux/types.h>
29*4882a593Smuzhiyun #include <linux/videodev2.h>
30*4882a593Smuzhiyun #include <media/videobuf2-dma-contig.h>
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #include "media-dev.h"
33*4882a593Smuzhiyun #include "fimc-is.h"
34*4882a593Smuzhiyun #include "fimc-is-command.h"
35*4882a593Smuzhiyun #include "fimc-is-errno.h"
36*4882a593Smuzhiyun #include "fimc-is-i2c.h"
37*4882a593Smuzhiyun #include "fimc-is-param.h"
38*4882a593Smuzhiyun #include "fimc-is-regs.h"
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun static char *fimc_is_clocks[ISS_CLKS_MAX] = {
42*4882a593Smuzhiyun 	[ISS_CLK_PPMUISPX]		= "ppmuispx",
43*4882a593Smuzhiyun 	[ISS_CLK_PPMUISPMX]		= "ppmuispmx",
44*4882a593Smuzhiyun 	[ISS_CLK_LITE0]			= "lite0",
45*4882a593Smuzhiyun 	[ISS_CLK_LITE1]			= "lite1",
46*4882a593Smuzhiyun 	[ISS_CLK_MPLL]			= "mpll",
47*4882a593Smuzhiyun 	[ISS_CLK_ISP]			= "isp",
48*4882a593Smuzhiyun 	[ISS_CLK_DRC]			= "drc",
49*4882a593Smuzhiyun 	[ISS_CLK_FD]			= "fd",
50*4882a593Smuzhiyun 	[ISS_CLK_MCUISP]		= "mcuisp",
51*4882a593Smuzhiyun 	[ISS_CLK_GICISP]		= "gicisp",
52*4882a593Smuzhiyun 	[ISS_CLK_PWM_ISP]		= "pwm_isp",
53*4882a593Smuzhiyun 	[ISS_CLK_MCUCTL_ISP]		= "mcuctl_isp",
54*4882a593Smuzhiyun 	[ISS_CLK_UART]			= "uart",
55*4882a593Smuzhiyun 	[ISS_CLK_ISP_DIV0]		= "ispdiv0",
56*4882a593Smuzhiyun 	[ISS_CLK_ISP_DIV1]		= "ispdiv1",
57*4882a593Smuzhiyun 	[ISS_CLK_MCUISP_DIV0]		= "mcuispdiv0",
58*4882a593Smuzhiyun 	[ISS_CLK_MCUISP_DIV1]		= "mcuispdiv1",
59*4882a593Smuzhiyun 	[ISS_CLK_ACLK200]		= "aclk200",
60*4882a593Smuzhiyun 	[ISS_CLK_ACLK200_DIV]		= "div_aclk200",
61*4882a593Smuzhiyun 	[ISS_CLK_ACLK400MCUISP]		= "aclk400mcuisp",
62*4882a593Smuzhiyun 	[ISS_CLK_ACLK400MCUISP_DIV]	= "div_aclk400mcuisp",
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun 
fimc_is_put_clocks(struct fimc_is * is)65*4882a593Smuzhiyun static void fimc_is_put_clocks(struct fimc_is *is)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	int i;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	for (i = 0; i < ISS_CLKS_MAX; i++) {
70*4882a593Smuzhiyun 		if (IS_ERR(is->clocks[i]))
71*4882a593Smuzhiyun 			continue;
72*4882a593Smuzhiyun 		clk_put(is->clocks[i]);
73*4882a593Smuzhiyun 		is->clocks[i] = ERR_PTR(-EINVAL);
74*4882a593Smuzhiyun 	}
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
fimc_is_get_clocks(struct fimc_is * is)77*4882a593Smuzhiyun static int fimc_is_get_clocks(struct fimc_is *is)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	int i, ret;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	for (i = 0; i < ISS_CLKS_MAX; i++)
82*4882a593Smuzhiyun 		is->clocks[i] = ERR_PTR(-EINVAL);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	for (i = 0; i < ISS_CLKS_MAX; i++) {
85*4882a593Smuzhiyun 		is->clocks[i] = clk_get(&is->pdev->dev, fimc_is_clocks[i]);
86*4882a593Smuzhiyun 		if (IS_ERR(is->clocks[i])) {
87*4882a593Smuzhiyun 			ret = PTR_ERR(is->clocks[i]);
88*4882a593Smuzhiyun 			goto err;
89*4882a593Smuzhiyun 		}
90*4882a593Smuzhiyun 	}
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	return 0;
93*4882a593Smuzhiyun err:
94*4882a593Smuzhiyun 	fimc_is_put_clocks(is);
95*4882a593Smuzhiyun 	dev_err(&is->pdev->dev, "failed to get clock: %s\n",
96*4882a593Smuzhiyun 		fimc_is_clocks[i]);
97*4882a593Smuzhiyun 	return ret;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
fimc_is_setup_clocks(struct fimc_is * is)100*4882a593Smuzhiyun static int fimc_is_setup_clocks(struct fimc_is *is)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	int ret;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	ret = clk_set_parent(is->clocks[ISS_CLK_ACLK200],
105*4882a593Smuzhiyun 					is->clocks[ISS_CLK_ACLK200_DIV]);
106*4882a593Smuzhiyun 	if (ret < 0)
107*4882a593Smuzhiyun 		return ret;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	ret = clk_set_parent(is->clocks[ISS_CLK_ACLK400MCUISP],
110*4882a593Smuzhiyun 					is->clocks[ISS_CLK_ACLK400MCUISP_DIV]);
111*4882a593Smuzhiyun 	if (ret < 0)
112*4882a593Smuzhiyun 		return ret;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	ret = clk_set_rate(is->clocks[ISS_CLK_ISP_DIV0], ACLK_AXI_FREQUENCY);
115*4882a593Smuzhiyun 	if (ret < 0)
116*4882a593Smuzhiyun 		return ret;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	ret = clk_set_rate(is->clocks[ISS_CLK_ISP_DIV1], ACLK_AXI_FREQUENCY);
119*4882a593Smuzhiyun 	if (ret < 0)
120*4882a593Smuzhiyun 		return ret;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	ret = clk_set_rate(is->clocks[ISS_CLK_MCUISP_DIV0],
123*4882a593Smuzhiyun 					ATCLK_MCUISP_FREQUENCY);
124*4882a593Smuzhiyun 	if (ret < 0)
125*4882a593Smuzhiyun 		return ret;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	return clk_set_rate(is->clocks[ISS_CLK_MCUISP_DIV1],
128*4882a593Smuzhiyun 					ATCLK_MCUISP_FREQUENCY);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
fimc_is_enable_clocks(struct fimc_is * is)131*4882a593Smuzhiyun static int fimc_is_enable_clocks(struct fimc_is *is)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	int i, ret;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	for (i = 0; i < ISS_GATE_CLKS_MAX; i++) {
136*4882a593Smuzhiyun 		if (IS_ERR(is->clocks[i]))
137*4882a593Smuzhiyun 			continue;
138*4882a593Smuzhiyun 		ret = clk_prepare_enable(is->clocks[i]);
139*4882a593Smuzhiyun 		if (ret < 0) {
140*4882a593Smuzhiyun 			dev_err(&is->pdev->dev, "clock %s enable failed\n",
141*4882a593Smuzhiyun 				fimc_is_clocks[i]);
142*4882a593Smuzhiyun 			for (--i; i >= 0; i--)
143*4882a593Smuzhiyun 				clk_disable_unprepare(is->clocks[i]);
144*4882a593Smuzhiyun 			return ret;
145*4882a593Smuzhiyun 		}
146*4882a593Smuzhiyun 		pr_debug("enabled clock: %s\n", fimc_is_clocks[i]);
147*4882a593Smuzhiyun 	}
148*4882a593Smuzhiyun 	return 0;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
fimc_is_disable_clocks(struct fimc_is * is)151*4882a593Smuzhiyun static void fimc_is_disable_clocks(struct fimc_is *is)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	int i;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	for (i = 0; i < ISS_GATE_CLKS_MAX; i++) {
156*4882a593Smuzhiyun 		if (!IS_ERR(is->clocks[i])) {
157*4882a593Smuzhiyun 			clk_disable_unprepare(is->clocks[i]);
158*4882a593Smuzhiyun 			pr_debug("disabled clock: %s\n", fimc_is_clocks[i]);
159*4882a593Smuzhiyun 		}
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
fimc_is_parse_sensor_config(struct fimc_is * is,unsigned int index,struct device_node * node)163*4882a593Smuzhiyun static int fimc_is_parse_sensor_config(struct fimc_is *is, unsigned int index,
164*4882a593Smuzhiyun 						struct device_node *node)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	struct fimc_is_sensor *sensor = &is->sensor[index];
167*4882a593Smuzhiyun 	struct device_node *ep, *port;
168*4882a593Smuzhiyun 	u32 tmp = 0;
169*4882a593Smuzhiyun 	int ret;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	sensor->drvdata = fimc_is_sensor_get_drvdata(node);
172*4882a593Smuzhiyun 	if (!sensor->drvdata) {
173*4882a593Smuzhiyun 		dev_err(&is->pdev->dev, "no driver data found for: %pOF\n",
174*4882a593Smuzhiyun 							 node);
175*4882a593Smuzhiyun 		return -EINVAL;
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	ep = of_graph_get_next_endpoint(node, NULL);
179*4882a593Smuzhiyun 	if (!ep)
180*4882a593Smuzhiyun 		return -ENXIO;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	port = of_graph_get_remote_port(ep);
183*4882a593Smuzhiyun 	of_node_put(ep);
184*4882a593Smuzhiyun 	if (!port)
185*4882a593Smuzhiyun 		return -ENXIO;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	/* Use MIPI-CSIS channel id to determine the ISP I2C bus index. */
188*4882a593Smuzhiyun 	ret = of_property_read_u32(port, "reg", &tmp);
189*4882a593Smuzhiyun 	if (ret < 0) {
190*4882a593Smuzhiyun 		dev_err(&is->pdev->dev, "reg property not found at: %pOF\n",
191*4882a593Smuzhiyun 							 port);
192*4882a593Smuzhiyun 		of_node_put(port);
193*4882a593Smuzhiyun 		return ret;
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	of_node_put(port);
197*4882a593Smuzhiyun 	sensor->i2c_bus = tmp - FIMC_INPUT_MIPI_CSI2_0;
198*4882a593Smuzhiyun 	return 0;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
fimc_is_register_subdevs(struct fimc_is * is)201*4882a593Smuzhiyun static int fimc_is_register_subdevs(struct fimc_is *is)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	struct device_node *i2c_bus, *child;
204*4882a593Smuzhiyun 	int ret, index = 0;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	ret = fimc_isp_subdev_create(&is->isp);
207*4882a593Smuzhiyun 	if (ret < 0)
208*4882a593Smuzhiyun 		return ret;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	for_each_compatible_node(i2c_bus, NULL, FIMC_IS_I2C_COMPATIBLE) {
211*4882a593Smuzhiyun 		for_each_available_child_of_node(i2c_bus, child) {
212*4882a593Smuzhiyun 			ret = fimc_is_parse_sensor_config(is, index, child);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 			if (ret < 0 || index >= FIMC_IS_SENSORS_NUM) {
215*4882a593Smuzhiyun 				of_node_put(child);
216*4882a593Smuzhiyun 				of_node_put(i2c_bus);
217*4882a593Smuzhiyun 				return ret;
218*4882a593Smuzhiyun 			}
219*4882a593Smuzhiyun 			index++;
220*4882a593Smuzhiyun 		}
221*4882a593Smuzhiyun 	}
222*4882a593Smuzhiyun 	return 0;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun 
fimc_is_unregister_subdevs(struct fimc_is * is)225*4882a593Smuzhiyun static int fimc_is_unregister_subdevs(struct fimc_is *is)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	fimc_isp_subdev_destroy(&is->isp);
228*4882a593Smuzhiyun 	return 0;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun 
fimc_is_load_setfile(struct fimc_is * is,char * file_name)231*4882a593Smuzhiyun static int fimc_is_load_setfile(struct fimc_is *is, char *file_name)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	const struct firmware *fw;
234*4882a593Smuzhiyun 	void *buf;
235*4882a593Smuzhiyun 	int ret;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	ret = request_firmware(&fw, file_name, &is->pdev->dev);
238*4882a593Smuzhiyun 	if (ret < 0) {
239*4882a593Smuzhiyun 		dev_err(&is->pdev->dev, "firmware request failed (%d)\n", ret);
240*4882a593Smuzhiyun 		return ret;
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 	buf = is->memory.vaddr + is->setfile.base;
243*4882a593Smuzhiyun 	memcpy(buf, fw->data, fw->size);
244*4882a593Smuzhiyun 	fimc_is_mem_barrier();
245*4882a593Smuzhiyun 	is->setfile.size = fw->size;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	pr_debug("mem vaddr: %p, setfile buf: %p\n", is->memory.vaddr, buf);
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	memcpy(is->fw.setfile_info,
250*4882a593Smuzhiyun 		fw->data + fw->size - FIMC_IS_SETFILE_INFO_LEN,
251*4882a593Smuzhiyun 		FIMC_IS_SETFILE_INFO_LEN - 1);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	is->fw.setfile_info[FIMC_IS_SETFILE_INFO_LEN - 1] = '\0';
254*4882a593Smuzhiyun 	is->setfile.state = 1;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	pr_debug("FIMC-IS setfile loaded: base: %#x, size: %zu B\n",
257*4882a593Smuzhiyun 		 is->setfile.base, fw->size);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	release_firmware(fw);
260*4882a593Smuzhiyun 	return ret;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
fimc_is_cpu_set_power(struct fimc_is * is,int on)263*4882a593Smuzhiyun int fimc_is_cpu_set_power(struct fimc_is *is, int on)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun 	unsigned int timeout = FIMC_IS_POWER_ON_TIMEOUT;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	if (on) {
268*4882a593Smuzhiyun 		/* Disable watchdog */
269*4882a593Smuzhiyun 		mcuctl_write(0, is, REG_WDT_ISP);
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 		/* Cortex-A5 start address setting */
272*4882a593Smuzhiyun 		mcuctl_write(is->memory.paddr, is, MCUCTL_REG_BBOAR);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 		/* Enable and start Cortex-A5 */
275*4882a593Smuzhiyun 		pmuisp_write(0x18000, is, REG_PMU_ISP_ARM_OPTION);
276*4882a593Smuzhiyun 		pmuisp_write(0x1, is, REG_PMU_ISP_ARM_CONFIGURATION);
277*4882a593Smuzhiyun 	} else {
278*4882a593Smuzhiyun 		/* A5 power off */
279*4882a593Smuzhiyun 		pmuisp_write(0x10000, is, REG_PMU_ISP_ARM_OPTION);
280*4882a593Smuzhiyun 		pmuisp_write(0x0, is, REG_PMU_ISP_ARM_CONFIGURATION);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 		while (pmuisp_read(is, REG_PMU_ISP_ARM_STATUS) & 1) {
283*4882a593Smuzhiyun 			if (timeout == 0)
284*4882a593Smuzhiyun 				return -ETIME;
285*4882a593Smuzhiyun 			timeout--;
286*4882a593Smuzhiyun 			udelay(1);
287*4882a593Smuzhiyun 		}
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	return 0;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun /* Wait until @bit of @is->state is set to @state in the interrupt handler. */
fimc_is_wait_event(struct fimc_is * is,unsigned long bit,unsigned int state,unsigned int timeout)294*4882a593Smuzhiyun int fimc_is_wait_event(struct fimc_is *is, unsigned long bit,
295*4882a593Smuzhiyun 		       unsigned int state, unsigned int timeout)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	int ret = wait_event_timeout(is->irq_queue,
299*4882a593Smuzhiyun 				     !state ^ test_bit(bit, &is->state),
300*4882a593Smuzhiyun 				     timeout);
301*4882a593Smuzhiyun 	if (ret == 0) {
302*4882a593Smuzhiyun 		dev_WARN(&is->pdev->dev, "%s() timed out\n", __func__);
303*4882a593Smuzhiyun 		return -ETIME;
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun 	return 0;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
fimc_is_start_firmware(struct fimc_is * is)308*4882a593Smuzhiyun int fimc_is_start_firmware(struct fimc_is *is)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun 	struct device *dev = &is->pdev->dev;
311*4882a593Smuzhiyun 	int ret;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	if (is->fw.f_w == NULL) {
314*4882a593Smuzhiyun 		dev_err(dev, "firmware is not loaded\n");
315*4882a593Smuzhiyun 		return -EINVAL;
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	memcpy(is->memory.vaddr, is->fw.f_w->data, is->fw.f_w->size);
319*4882a593Smuzhiyun 	wmb();
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	ret = fimc_is_cpu_set_power(is, 1);
322*4882a593Smuzhiyun 	if (ret < 0)
323*4882a593Smuzhiyun 		return ret;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	ret = fimc_is_wait_event(is, IS_ST_A5_PWR_ON, 1,
326*4882a593Smuzhiyun 				 msecs_to_jiffies(FIMC_IS_FW_LOAD_TIMEOUT));
327*4882a593Smuzhiyun 	if (ret < 0)
328*4882a593Smuzhiyun 		dev_err(dev, "FIMC-IS CPU power on failed\n");
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	return ret;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun /* Allocate working memory for the FIMC-IS CPU. */
fimc_is_alloc_cpu_memory(struct fimc_is * is)334*4882a593Smuzhiyun static int fimc_is_alloc_cpu_memory(struct fimc_is *is)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	struct device *dev = &is->pdev->dev;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	is->memory.vaddr = dma_alloc_coherent(dev, FIMC_IS_CPU_MEM_SIZE,
339*4882a593Smuzhiyun 					      &is->memory.paddr, GFP_KERNEL);
340*4882a593Smuzhiyun 	if (is->memory.vaddr == NULL)
341*4882a593Smuzhiyun 		return -ENOMEM;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	is->memory.size = FIMC_IS_CPU_MEM_SIZE;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	dev_info(dev, "FIMC-IS CPU memory base: %#x\n", (u32)is->memory.paddr);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	if (((u32)is->memory.paddr) & FIMC_IS_FW_ADDR_MASK) {
348*4882a593Smuzhiyun 		dev_err(dev, "invalid firmware memory alignment: %#x\n",
349*4882a593Smuzhiyun 			(u32)is->memory.paddr);
350*4882a593Smuzhiyun 		dma_free_coherent(dev, is->memory.size, is->memory.vaddr,
351*4882a593Smuzhiyun 				  is->memory.paddr);
352*4882a593Smuzhiyun 		return -EIO;
353*4882a593Smuzhiyun 	}
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	is->is_p_region = (struct is_region *)(is->memory.vaddr +
356*4882a593Smuzhiyun 				FIMC_IS_CPU_MEM_SIZE - FIMC_IS_REGION_SIZE);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	is->is_dma_p_region = is->memory.paddr +
359*4882a593Smuzhiyun 				FIMC_IS_CPU_MEM_SIZE - FIMC_IS_REGION_SIZE;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	is->is_shared_region = (struct is_share_region *)(is->memory.vaddr +
362*4882a593Smuzhiyun 				FIMC_IS_SHARED_REGION_OFFSET);
363*4882a593Smuzhiyun 	return 0;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun 
fimc_is_free_cpu_memory(struct fimc_is * is)366*4882a593Smuzhiyun static void fimc_is_free_cpu_memory(struct fimc_is *is)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	struct device *dev = &is->pdev->dev;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	if (is->memory.vaddr == NULL)
371*4882a593Smuzhiyun 		return;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	dma_free_coherent(dev, is->memory.size, is->memory.vaddr,
374*4882a593Smuzhiyun 			  is->memory.paddr);
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun 
fimc_is_load_firmware(const struct firmware * fw,void * context)377*4882a593Smuzhiyun static void fimc_is_load_firmware(const struct firmware *fw, void *context)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun 	struct fimc_is *is = context;
380*4882a593Smuzhiyun 	struct device *dev = &is->pdev->dev;
381*4882a593Smuzhiyun 	void *buf;
382*4882a593Smuzhiyun 	int ret;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (fw == NULL) {
385*4882a593Smuzhiyun 		dev_err(dev, "firmware request failed\n");
386*4882a593Smuzhiyun 		return;
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 	mutex_lock(&is->lock);
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	if (fw->size < FIMC_IS_FW_SIZE_MIN || fw->size > FIMC_IS_FW_SIZE_MAX) {
391*4882a593Smuzhiyun 		dev_err(dev, "wrong firmware size: %zu\n", fw->size);
392*4882a593Smuzhiyun 		goto done;
393*4882a593Smuzhiyun 	}
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	is->fw.size = fw->size;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	ret = fimc_is_alloc_cpu_memory(is);
398*4882a593Smuzhiyun 	if (ret < 0) {
399*4882a593Smuzhiyun 		dev_err(dev, "failed to allocate FIMC-IS CPU memory\n");
400*4882a593Smuzhiyun 		goto done;
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	memcpy(is->memory.vaddr, fw->data, fw->size);
404*4882a593Smuzhiyun 	wmb();
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	/* Read firmware description. */
407*4882a593Smuzhiyun 	buf = (void *)(is->memory.vaddr + fw->size - FIMC_IS_FW_DESC_LEN);
408*4882a593Smuzhiyun 	memcpy(&is->fw.info, buf, FIMC_IS_FW_INFO_LEN);
409*4882a593Smuzhiyun 	is->fw.info[FIMC_IS_FW_INFO_LEN] = 0;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	buf = (void *)(is->memory.vaddr + fw->size - FIMC_IS_FW_VER_LEN);
412*4882a593Smuzhiyun 	memcpy(&is->fw.version, buf, FIMC_IS_FW_VER_LEN);
413*4882a593Smuzhiyun 	is->fw.version[FIMC_IS_FW_VER_LEN - 1] = 0;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	is->fw.state = 1;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	dev_info(dev, "loaded firmware: %s, rev. %s\n",
418*4882a593Smuzhiyun 		 is->fw.info, is->fw.version);
419*4882a593Smuzhiyun 	dev_dbg(dev, "FW size: %zu, paddr: %pad\n", fw->size, &is->memory.paddr);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	is->is_shared_region->chip_id = 0xe4412;
422*4882a593Smuzhiyun 	is->is_shared_region->chip_rev_no = 1;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	fimc_is_mem_barrier();
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	/*
427*4882a593Smuzhiyun 	 * FIXME: The firmware is not being released for now, as it is
428*4882a593Smuzhiyun 	 * needed around for copying to the IS working memory every
429*4882a593Smuzhiyun 	 * time before the Cortex-A5 is restarted.
430*4882a593Smuzhiyun 	 */
431*4882a593Smuzhiyun 	release_firmware(is->fw.f_w);
432*4882a593Smuzhiyun 	is->fw.f_w = fw;
433*4882a593Smuzhiyun done:
434*4882a593Smuzhiyun 	mutex_unlock(&is->lock);
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun 
fimc_is_request_firmware(struct fimc_is * is,const char * fw_name)437*4882a593Smuzhiyun static int fimc_is_request_firmware(struct fimc_is *is, const char *fw_name)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun 	return request_firmware_nowait(THIS_MODULE,
440*4882a593Smuzhiyun 				FW_ACTION_HOTPLUG, fw_name, &is->pdev->dev,
441*4882a593Smuzhiyun 				GFP_KERNEL, is, fimc_is_load_firmware);
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun /* General IS interrupt handler */
fimc_is_general_irq_handler(struct fimc_is * is)445*4882a593Smuzhiyun static void fimc_is_general_irq_handler(struct fimc_is *is)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun 	is->i2h_cmd.cmd = mcuctl_read(is, MCUCTL_REG_ISSR(10));
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	switch (is->i2h_cmd.cmd) {
450*4882a593Smuzhiyun 	case IHC_GET_SENSOR_NUM:
451*4882a593Smuzhiyun 		fimc_is_hw_get_params(is, 1);
452*4882a593Smuzhiyun 		fimc_is_hw_wait_intmsr0_intmsd0(is);
453*4882a593Smuzhiyun 		fimc_is_hw_set_sensor_num(is);
454*4882a593Smuzhiyun 		pr_debug("ISP FW version: %#x\n", is->i2h_cmd.args[0]);
455*4882a593Smuzhiyun 		break;
456*4882a593Smuzhiyun 	case IHC_SET_FACE_MARK:
457*4882a593Smuzhiyun 	case IHC_FRAME_DONE:
458*4882a593Smuzhiyun 		fimc_is_hw_get_params(is, 2);
459*4882a593Smuzhiyun 		break;
460*4882a593Smuzhiyun 	case IHC_SET_SHOT_MARK:
461*4882a593Smuzhiyun 	case IHC_AA_DONE:
462*4882a593Smuzhiyun 	case IH_REPLY_DONE:
463*4882a593Smuzhiyun 		fimc_is_hw_get_params(is, 3);
464*4882a593Smuzhiyun 		break;
465*4882a593Smuzhiyun 	case IH_REPLY_NOT_DONE:
466*4882a593Smuzhiyun 		fimc_is_hw_get_params(is, 4);
467*4882a593Smuzhiyun 		break;
468*4882a593Smuzhiyun 	case IHC_NOT_READY:
469*4882a593Smuzhiyun 		break;
470*4882a593Smuzhiyun 	default:
471*4882a593Smuzhiyun 		pr_info("unknown command: %#x\n", is->i2h_cmd.cmd);
472*4882a593Smuzhiyun 	}
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	fimc_is_fw_clear_irq1(is, FIMC_IS_INT_GENERAL);
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	switch (is->i2h_cmd.cmd) {
477*4882a593Smuzhiyun 	case IHC_GET_SENSOR_NUM:
478*4882a593Smuzhiyun 		fimc_is_hw_set_intgr0_gd0(is);
479*4882a593Smuzhiyun 		set_bit(IS_ST_A5_PWR_ON, &is->state);
480*4882a593Smuzhiyun 		break;
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	case IHC_SET_SHOT_MARK:
483*4882a593Smuzhiyun 		break;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	case IHC_SET_FACE_MARK:
486*4882a593Smuzhiyun 		is->fd_header.count = is->i2h_cmd.args[0];
487*4882a593Smuzhiyun 		is->fd_header.index = is->i2h_cmd.args[1];
488*4882a593Smuzhiyun 		is->fd_header.offset = 0;
489*4882a593Smuzhiyun 		break;
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	case IHC_FRAME_DONE:
492*4882a593Smuzhiyun 		break;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	case IHC_AA_DONE:
495*4882a593Smuzhiyun 		pr_debug("AA_DONE - %d, %d, %d\n", is->i2h_cmd.args[0],
496*4882a593Smuzhiyun 			 is->i2h_cmd.args[1], is->i2h_cmd.args[2]);
497*4882a593Smuzhiyun 		break;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	case IH_REPLY_DONE:
500*4882a593Smuzhiyun 		pr_debug("ISR_DONE: args[0]: %#x\n", is->i2h_cmd.args[0]);
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 		switch (is->i2h_cmd.args[0]) {
503*4882a593Smuzhiyun 		case HIC_PREVIEW_STILL...HIC_CAPTURE_VIDEO:
504*4882a593Smuzhiyun 			/* Get CAC margin */
505*4882a593Smuzhiyun 			set_bit(IS_ST_CHANGE_MODE, &is->state);
506*4882a593Smuzhiyun 			is->isp.cac_margin_x = is->i2h_cmd.args[1];
507*4882a593Smuzhiyun 			is->isp.cac_margin_y = is->i2h_cmd.args[2];
508*4882a593Smuzhiyun 			pr_debug("CAC margin (x,y): (%d,%d)\n",
509*4882a593Smuzhiyun 				 is->isp.cac_margin_x, is->isp.cac_margin_y);
510*4882a593Smuzhiyun 			break;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 		case HIC_STREAM_ON:
513*4882a593Smuzhiyun 			clear_bit(IS_ST_STREAM_OFF, &is->state);
514*4882a593Smuzhiyun 			set_bit(IS_ST_STREAM_ON, &is->state);
515*4882a593Smuzhiyun 			break;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 		case HIC_STREAM_OFF:
518*4882a593Smuzhiyun 			clear_bit(IS_ST_STREAM_ON, &is->state);
519*4882a593Smuzhiyun 			set_bit(IS_ST_STREAM_OFF, &is->state);
520*4882a593Smuzhiyun 			break;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 		case HIC_SET_PARAMETER:
523*4882a593Smuzhiyun 			is->config[is->config_index].p_region_index[0] = 0;
524*4882a593Smuzhiyun 			is->config[is->config_index].p_region_index[1] = 0;
525*4882a593Smuzhiyun 			set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state);
526*4882a593Smuzhiyun 			pr_debug("HIC_SET_PARAMETER\n");
527*4882a593Smuzhiyun 			break;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 		case HIC_GET_PARAMETER:
530*4882a593Smuzhiyun 			break;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 		case HIC_SET_TUNE:
533*4882a593Smuzhiyun 			break;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 		case HIC_GET_STATUS:
536*4882a593Smuzhiyun 			break;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 		case HIC_OPEN_SENSOR:
539*4882a593Smuzhiyun 			set_bit(IS_ST_OPEN_SENSOR, &is->state);
540*4882a593Smuzhiyun 			pr_debug("data lanes: %d, settle line: %d\n",
541*4882a593Smuzhiyun 				 is->i2h_cmd.args[2], is->i2h_cmd.args[1]);
542*4882a593Smuzhiyun 			break;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 		case HIC_CLOSE_SENSOR:
545*4882a593Smuzhiyun 			clear_bit(IS_ST_OPEN_SENSOR, &is->state);
546*4882a593Smuzhiyun 			is->sensor_index = 0;
547*4882a593Smuzhiyun 			break;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 		case HIC_MSG_TEST:
550*4882a593Smuzhiyun 			pr_debug("config MSG level completed\n");
551*4882a593Smuzhiyun 			break;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 		case HIC_POWER_DOWN:
554*4882a593Smuzhiyun 			clear_bit(IS_ST_PWR_SUBIP_ON, &is->state);
555*4882a593Smuzhiyun 			break;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 		case HIC_GET_SET_FILE_ADDR:
558*4882a593Smuzhiyun 			is->setfile.base = is->i2h_cmd.args[1];
559*4882a593Smuzhiyun 			set_bit(IS_ST_SETFILE_LOADED, &is->state);
560*4882a593Smuzhiyun 			break;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 		case HIC_LOAD_SET_FILE:
563*4882a593Smuzhiyun 			set_bit(IS_ST_SETFILE_LOADED, &is->state);
564*4882a593Smuzhiyun 			break;
565*4882a593Smuzhiyun 		}
566*4882a593Smuzhiyun 		break;
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	case IH_REPLY_NOT_DONE:
569*4882a593Smuzhiyun 		pr_err("ISR_NDONE: %d: %#x, %s\n", is->i2h_cmd.args[0],
570*4882a593Smuzhiyun 		       is->i2h_cmd.args[1],
571*4882a593Smuzhiyun 		       fimc_is_strerr(is->i2h_cmd.args[1]));
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 		if (is->i2h_cmd.args[1] & IS_ERROR_TIME_OUT_FLAG)
574*4882a593Smuzhiyun 			pr_err("IS_ERROR_TIME_OUT\n");
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 		switch (is->i2h_cmd.args[1]) {
577*4882a593Smuzhiyun 		case IS_ERROR_SET_PARAMETER:
578*4882a593Smuzhiyun 			fimc_is_mem_barrier();
579*4882a593Smuzhiyun 		}
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 		switch (is->i2h_cmd.args[0]) {
582*4882a593Smuzhiyun 		case HIC_SET_PARAMETER:
583*4882a593Smuzhiyun 			is->config[is->config_index].p_region_index[0] = 0;
584*4882a593Smuzhiyun 			is->config[is->config_index].p_region_index[1] = 0;
585*4882a593Smuzhiyun 			set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state);
586*4882a593Smuzhiyun 			break;
587*4882a593Smuzhiyun 		}
588*4882a593Smuzhiyun 		break;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	case IHC_NOT_READY:
591*4882a593Smuzhiyun 		pr_err("IS control sequence error: Not Ready\n");
592*4882a593Smuzhiyun 		break;
593*4882a593Smuzhiyun 	}
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	wake_up(&is->irq_queue);
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun 
fimc_is_irq_handler(int irq,void * priv)598*4882a593Smuzhiyun static irqreturn_t fimc_is_irq_handler(int irq, void *priv)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun 	struct fimc_is *is = priv;
601*4882a593Smuzhiyun 	unsigned long flags;
602*4882a593Smuzhiyun 	u32 status;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	spin_lock_irqsave(&is->slock, flags);
605*4882a593Smuzhiyun 	status = mcuctl_read(is, MCUCTL_REG_INTSR1);
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	if (status & (1UL << FIMC_IS_INT_GENERAL))
608*4882a593Smuzhiyun 		fimc_is_general_irq_handler(is);
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	if (status & (1UL << FIMC_IS_INT_FRAME_DONE_ISP))
611*4882a593Smuzhiyun 		fimc_isp_irq_handler(is);
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	spin_unlock_irqrestore(&is->slock, flags);
614*4882a593Smuzhiyun 	return IRQ_HANDLED;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun 
fimc_is_hw_open_sensor(struct fimc_is * is,struct fimc_is_sensor * sensor)617*4882a593Smuzhiyun static int fimc_is_hw_open_sensor(struct fimc_is *is,
618*4882a593Smuzhiyun 				  struct fimc_is_sensor *sensor)
619*4882a593Smuzhiyun {
620*4882a593Smuzhiyun 	struct sensor_open_extended *soe = (void *)&is->is_p_region->shared;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	fimc_is_hw_wait_intmsr0_intmsd0(is);
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	soe->self_calibration_mode = 1;
625*4882a593Smuzhiyun 	soe->actuator_type = 0;
626*4882a593Smuzhiyun 	soe->mipi_lane_num = 0;
627*4882a593Smuzhiyun 	soe->mclk = 0;
628*4882a593Smuzhiyun 	soe->mipi_speed	= 0;
629*4882a593Smuzhiyun 	soe->fast_open_sensor = 0;
630*4882a593Smuzhiyun 	soe->i2c_sclk = 88000000;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	fimc_is_mem_barrier();
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	/*
635*4882a593Smuzhiyun 	 * Some user space use cases hang up here without this
636*4882a593Smuzhiyun 	 * empirically chosen delay.
637*4882a593Smuzhiyun 	 */
638*4882a593Smuzhiyun 	udelay(100);
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	mcuctl_write(HIC_OPEN_SENSOR, is, MCUCTL_REG_ISSR(0));
641*4882a593Smuzhiyun 	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
642*4882a593Smuzhiyun 	mcuctl_write(sensor->drvdata->id, is, MCUCTL_REG_ISSR(2));
643*4882a593Smuzhiyun 	mcuctl_write(sensor->i2c_bus, is, MCUCTL_REG_ISSR(3));
644*4882a593Smuzhiyun 	mcuctl_write(is->is_dma_p_region, is, MCUCTL_REG_ISSR(4));
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	fimc_is_hw_set_intgr0_gd0(is);
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	return fimc_is_wait_event(is, IS_ST_OPEN_SENSOR, 1,
649*4882a593Smuzhiyun 				  sensor->drvdata->open_timeout);
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 
fimc_is_hw_initialize(struct fimc_is * is)653*4882a593Smuzhiyun int fimc_is_hw_initialize(struct fimc_is *is)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun 	static const int config_ids[] = {
656*4882a593Smuzhiyun 		IS_SC_PREVIEW_STILL, IS_SC_PREVIEW_VIDEO,
657*4882a593Smuzhiyun 		IS_SC_CAPTURE_STILL, IS_SC_CAPTURE_VIDEO
658*4882a593Smuzhiyun 	};
659*4882a593Smuzhiyun 	struct device *dev = &is->pdev->dev;
660*4882a593Smuzhiyun 	u32 prev_id;
661*4882a593Smuzhiyun 	int i, ret;
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	/* Sensor initialization. Only one sensor is currently supported. */
664*4882a593Smuzhiyun 	ret = fimc_is_hw_open_sensor(is, &is->sensor[0]);
665*4882a593Smuzhiyun 	if (ret < 0)
666*4882a593Smuzhiyun 		return ret;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	/* Get the setfile address. */
669*4882a593Smuzhiyun 	fimc_is_hw_get_setfile_addr(is);
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	ret = fimc_is_wait_event(is, IS_ST_SETFILE_LOADED, 1,
672*4882a593Smuzhiyun 				 FIMC_IS_CONFIG_TIMEOUT);
673*4882a593Smuzhiyun 	if (ret < 0) {
674*4882a593Smuzhiyun 		dev_err(dev, "get setfile address timed out\n");
675*4882a593Smuzhiyun 		return ret;
676*4882a593Smuzhiyun 	}
677*4882a593Smuzhiyun 	pr_debug("setfile.base: %#x\n", is->setfile.base);
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	/* Load the setfile. */
680*4882a593Smuzhiyun 	fimc_is_load_setfile(is, FIMC_IS_SETFILE_6A3);
681*4882a593Smuzhiyun 	clear_bit(IS_ST_SETFILE_LOADED, &is->state);
682*4882a593Smuzhiyun 	fimc_is_hw_load_setfile(is);
683*4882a593Smuzhiyun 	ret = fimc_is_wait_event(is, IS_ST_SETFILE_LOADED, 1,
684*4882a593Smuzhiyun 				 FIMC_IS_CONFIG_TIMEOUT);
685*4882a593Smuzhiyun 	if (ret < 0) {
686*4882a593Smuzhiyun 		dev_err(dev, "loading setfile timed out\n");
687*4882a593Smuzhiyun 		return ret;
688*4882a593Smuzhiyun 	}
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	pr_debug("setfile: base: %#x, size: %d\n",
691*4882a593Smuzhiyun 		 is->setfile.base, is->setfile.size);
692*4882a593Smuzhiyun 	pr_info("FIMC-IS Setfile info: %s\n", is->fw.setfile_info);
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	/* Check magic number. */
695*4882a593Smuzhiyun 	if (is->is_p_region->shared[MAX_SHARED_COUNT - 1] !=
696*4882a593Smuzhiyun 	    FIMC_IS_MAGIC_NUMBER) {
697*4882a593Smuzhiyun 		dev_err(dev, "magic number error!\n");
698*4882a593Smuzhiyun 		return -EIO;
699*4882a593Smuzhiyun 	}
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	pr_debug("shared region: %pad, parameter region: %pad\n",
702*4882a593Smuzhiyun 		 &is->memory.paddr + FIMC_IS_SHARED_REGION_OFFSET,
703*4882a593Smuzhiyun 		 &is->is_dma_p_region);
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	is->setfile.sub_index = 0;
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	/* Stream off. */
708*4882a593Smuzhiyun 	fimc_is_hw_stream_off(is);
709*4882a593Smuzhiyun 	ret = fimc_is_wait_event(is, IS_ST_STREAM_OFF, 1,
710*4882a593Smuzhiyun 				 FIMC_IS_CONFIG_TIMEOUT);
711*4882a593Smuzhiyun 	if (ret < 0) {
712*4882a593Smuzhiyun 		dev_err(dev, "stream off timeout\n");
713*4882a593Smuzhiyun 		return ret;
714*4882a593Smuzhiyun 	}
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	/* Preserve previous mode. */
717*4882a593Smuzhiyun 	prev_id = is->config_index;
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	/* Set initial parameter values. */
720*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(config_ids); i++) {
721*4882a593Smuzhiyun 		is->config_index = config_ids[i];
722*4882a593Smuzhiyun 		fimc_is_set_initial_params(is);
723*4882a593Smuzhiyun 		ret = fimc_is_itf_s_param(is, true);
724*4882a593Smuzhiyun 		if (ret < 0) {
725*4882a593Smuzhiyun 			is->config_index = prev_id;
726*4882a593Smuzhiyun 			return ret;
727*4882a593Smuzhiyun 		}
728*4882a593Smuzhiyun 	}
729*4882a593Smuzhiyun 	is->config_index = prev_id;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	set_bit(IS_ST_INIT_DONE, &is->state);
732*4882a593Smuzhiyun 	dev_info(dev, "initialization sequence completed (%d)\n",
733*4882a593Smuzhiyun 						is->config_index);
734*4882a593Smuzhiyun 	return 0;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun 
fimc_is_show(struct seq_file * s,void * data)737*4882a593Smuzhiyun static int fimc_is_show(struct seq_file *s, void *data)
738*4882a593Smuzhiyun {
739*4882a593Smuzhiyun 	struct fimc_is *is = s->private;
740*4882a593Smuzhiyun 	const u8 *buf = is->memory.vaddr + FIMC_IS_DEBUG_REGION_OFFSET;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	if (is->memory.vaddr == NULL) {
743*4882a593Smuzhiyun 		dev_err(&is->pdev->dev, "firmware memory is not initialized\n");
744*4882a593Smuzhiyun 		return -EIO;
745*4882a593Smuzhiyun 	}
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	seq_printf(s, "%s\n", buf);
748*4882a593Smuzhiyun 	return 0;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun DEFINE_SHOW_ATTRIBUTE(fimc_is);
752*4882a593Smuzhiyun 
fimc_is_debugfs_remove(struct fimc_is * is)753*4882a593Smuzhiyun static void fimc_is_debugfs_remove(struct fimc_is *is)
754*4882a593Smuzhiyun {
755*4882a593Smuzhiyun 	debugfs_remove_recursive(is->debugfs_entry);
756*4882a593Smuzhiyun 	is->debugfs_entry = NULL;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun 
fimc_is_debugfs_create(struct fimc_is * is)759*4882a593Smuzhiyun static void fimc_is_debugfs_create(struct fimc_is *is)
760*4882a593Smuzhiyun {
761*4882a593Smuzhiyun 	is->debugfs_entry = debugfs_create_dir("fimc_is", NULL);
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	debugfs_create_file("fw_log", S_IRUGO, is->debugfs_entry, is,
764*4882a593Smuzhiyun 			    &fimc_is_fops);
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun static int fimc_is_runtime_resume(struct device *dev);
768*4882a593Smuzhiyun static int fimc_is_runtime_suspend(struct device *dev);
769*4882a593Smuzhiyun 
fimc_is_probe(struct platform_device * pdev)770*4882a593Smuzhiyun static int fimc_is_probe(struct platform_device *pdev)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
773*4882a593Smuzhiyun 	struct fimc_is *is;
774*4882a593Smuzhiyun 	struct resource res;
775*4882a593Smuzhiyun 	struct device_node *node;
776*4882a593Smuzhiyun 	int ret;
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	is = devm_kzalloc(&pdev->dev, sizeof(*is), GFP_KERNEL);
779*4882a593Smuzhiyun 	if (!is)
780*4882a593Smuzhiyun 		return -ENOMEM;
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	is->pdev = pdev;
783*4882a593Smuzhiyun 	is->isp.pdev = pdev;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	init_waitqueue_head(&is->irq_queue);
786*4882a593Smuzhiyun 	spin_lock_init(&is->slock);
787*4882a593Smuzhiyun 	mutex_init(&is->lock);
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 	ret = of_address_to_resource(dev->of_node, 0, &res);
790*4882a593Smuzhiyun 	if (ret < 0)
791*4882a593Smuzhiyun 		return ret;
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	is->regs = devm_ioremap_resource(dev, &res);
794*4882a593Smuzhiyun 	if (IS_ERR(is->regs))
795*4882a593Smuzhiyun 		return PTR_ERR(is->regs);
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	node = of_get_child_by_name(dev->of_node, "pmu");
798*4882a593Smuzhiyun 	if (!node)
799*4882a593Smuzhiyun 		return -ENODEV;
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	is->pmu_regs = of_iomap(node, 0);
802*4882a593Smuzhiyun 	of_node_put(node);
803*4882a593Smuzhiyun 	if (!is->pmu_regs)
804*4882a593Smuzhiyun 		return -ENOMEM;
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	is->irq = irq_of_parse_and_map(dev->of_node, 0);
807*4882a593Smuzhiyun 	if (!is->irq) {
808*4882a593Smuzhiyun 		dev_err(dev, "no irq found\n");
809*4882a593Smuzhiyun 		ret = -EINVAL;
810*4882a593Smuzhiyun 		goto err_iounmap;
811*4882a593Smuzhiyun 	}
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun 	ret = fimc_is_get_clocks(is);
814*4882a593Smuzhiyun 	if (ret < 0)
815*4882a593Smuzhiyun 		goto err_iounmap;
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	platform_set_drvdata(pdev, is);
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	ret = request_irq(is->irq, fimc_is_irq_handler, 0, dev_name(dev), is);
820*4882a593Smuzhiyun 	if (ret < 0) {
821*4882a593Smuzhiyun 		dev_err(dev, "irq request failed\n");
822*4882a593Smuzhiyun 		goto err_clk;
823*4882a593Smuzhiyun 	}
824*4882a593Smuzhiyun 	pm_runtime_enable(dev);
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 	if (!pm_runtime_enabled(dev)) {
827*4882a593Smuzhiyun 		ret = fimc_is_runtime_resume(dev);
828*4882a593Smuzhiyun 		if (ret < 0)
829*4882a593Smuzhiyun 			goto err_irq;
830*4882a593Smuzhiyun 	}
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 	ret = pm_runtime_resume_and_get(dev);
833*4882a593Smuzhiyun 	if (ret < 0)
834*4882a593Smuzhiyun 		goto err_pm_disable;
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 	vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun 	ret = devm_of_platform_populate(dev);
839*4882a593Smuzhiyun 	if (ret < 0)
840*4882a593Smuzhiyun 		goto err_pm;
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	/*
843*4882a593Smuzhiyun 	 * Register FIMC-IS V4L2 subdevs to this driver. The video nodes
844*4882a593Smuzhiyun 	 * will be created within the subdev's registered() callback.
845*4882a593Smuzhiyun 	 */
846*4882a593Smuzhiyun 	ret = fimc_is_register_subdevs(is);
847*4882a593Smuzhiyun 	if (ret < 0)
848*4882a593Smuzhiyun 		goto err_pm;
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	fimc_is_debugfs_create(is);
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 	ret = fimc_is_request_firmware(is, FIMC_IS_FW_FILENAME);
853*4882a593Smuzhiyun 	if (ret < 0)
854*4882a593Smuzhiyun 		goto err_dfs;
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 	pm_runtime_put_sync(dev);
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun 	dev_dbg(dev, "FIMC-IS registered successfully\n");
859*4882a593Smuzhiyun 	return 0;
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun err_dfs:
862*4882a593Smuzhiyun 	fimc_is_debugfs_remove(is);
863*4882a593Smuzhiyun 	fimc_is_unregister_subdevs(is);
864*4882a593Smuzhiyun err_pm:
865*4882a593Smuzhiyun 	pm_runtime_put_noidle(dev);
866*4882a593Smuzhiyun 	if (!pm_runtime_enabled(dev))
867*4882a593Smuzhiyun 		fimc_is_runtime_suspend(dev);
868*4882a593Smuzhiyun err_pm_disable:
869*4882a593Smuzhiyun 	pm_runtime_disable(dev);
870*4882a593Smuzhiyun err_irq:
871*4882a593Smuzhiyun 	free_irq(is->irq, is);
872*4882a593Smuzhiyun err_clk:
873*4882a593Smuzhiyun 	fimc_is_put_clocks(is);
874*4882a593Smuzhiyun err_iounmap:
875*4882a593Smuzhiyun 	iounmap(is->pmu_regs);
876*4882a593Smuzhiyun 	return ret;
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun 
fimc_is_runtime_resume(struct device * dev)879*4882a593Smuzhiyun static int fimc_is_runtime_resume(struct device *dev)
880*4882a593Smuzhiyun {
881*4882a593Smuzhiyun 	struct fimc_is *is = dev_get_drvdata(dev);
882*4882a593Smuzhiyun 	int ret;
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	ret = fimc_is_setup_clocks(is);
885*4882a593Smuzhiyun 	if (ret)
886*4882a593Smuzhiyun 		return ret;
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 	return fimc_is_enable_clocks(is);
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun 
fimc_is_runtime_suspend(struct device * dev)891*4882a593Smuzhiyun static int fimc_is_runtime_suspend(struct device *dev)
892*4882a593Smuzhiyun {
893*4882a593Smuzhiyun 	struct fimc_is *is = dev_get_drvdata(dev);
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	fimc_is_disable_clocks(is);
896*4882a593Smuzhiyun 	return 0;
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
fimc_is_resume(struct device * dev)900*4882a593Smuzhiyun static int fimc_is_resume(struct device *dev)
901*4882a593Smuzhiyun {
902*4882a593Smuzhiyun 	/* TODO: */
903*4882a593Smuzhiyun 	return 0;
904*4882a593Smuzhiyun }
905*4882a593Smuzhiyun 
fimc_is_suspend(struct device * dev)906*4882a593Smuzhiyun static int fimc_is_suspend(struct device *dev)
907*4882a593Smuzhiyun {
908*4882a593Smuzhiyun 	struct fimc_is *is = dev_get_drvdata(dev);
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	/* TODO: */
911*4882a593Smuzhiyun 	if (test_bit(IS_ST_A5_PWR_ON, &is->state))
912*4882a593Smuzhiyun 		return -EBUSY;
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	return 0;
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun #endif /* CONFIG_PM_SLEEP */
917*4882a593Smuzhiyun 
fimc_is_remove(struct platform_device * pdev)918*4882a593Smuzhiyun static int fimc_is_remove(struct platform_device *pdev)
919*4882a593Smuzhiyun {
920*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
921*4882a593Smuzhiyun 	struct fimc_is *is = dev_get_drvdata(dev);
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	pm_runtime_disable(dev);
924*4882a593Smuzhiyun 	pm_runtime_set_suspended(dev);
925*4882a593Smuzhiyun 	if (!pm_runtime_status_suspended(dev))
926*4882a593Smuzhiyun 		fimc_is_runtime_suspend(dev);
927*4882a593Smuzhiyun 	free_irq(is->irq, is);
928*4882a593Smuzhiyun 	fimc_is_unregister_subdevs(is);
929*4882a593Smuzhiyun 	vb2_dma_contig_clear_max_seg_size(dev);
930*4882a593Smuzhiyun 	fimc_is_put_clocks(is);
931*4882a593Smuzhiyun 	iounmap(is->pmu_regs);
932*4882a593Smuzhiyun 	fimc_is_debugfs_remove(is);
933*4882a593Smuzhiyun 	release_firmware(is->fw.f_w);
934*4882a593Smuzhiyun 	fimc_is_free_cpu_memory(is);
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	return 0;
937*4882a593Smuzhiyun }
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun static const struct of_device_id fimc_is_of_match[] = {
940*4882a593Smuzhiyun 	{ .compatible = "samsung,exynos4212-fimc-is" },
941*4882a593Smuzhiyun 	{ /* sentinel */ },
942*4882a593Smuzhiyun };
943*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, fimc_is_of_match);
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun static const struct dev_pm_ops fimc_is_pm_ops = {
946*4882a593Smuzhiyun 	SET_SYSTEM_SLEEP_PM_OPS(fimc_is_suspend, fimc_is_resume)
947*4882a593Smuzhiyun 	SET_RUNTIME_PM_OPS(fimc_is_runtime_suspend, fimc_is_runtime_resume,
948*4882a593Smuzhiyun 			   NULL)
949*4882a593Smuzhiyun };
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun static struct platform_driver fimc_is_driver = {
952*4882a593Smuzhiyun 	.probe		= fimc_is_probe,
953*4882a593Smuzhiyun 	.remove		= fimc_is_remove,
954*4882a593Smuzhiyun 	.driver = {
955*4882a593Smuzhiyun 		.of_match_table	= fimc_is_of_match,
956*4882a593Smuzhiyun 		.name		= FIMC_IS_DRV_NAME,
957*4882a593Smuzhiyun 		.pm		= &fimc_is_pm_ops,
958*4882a593Smuzhiyun 	}
959*4882a593Smuzhiyun };
960*4882a593Smuzhiyun 
fimc_is_module_init(void)961*4882a593Smuzhiyun static int fimc_is_module_init(void)
962*4882a593Smuzhiyun {
963*4882a593Smuzhiyun 	int ret;
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	ret = fimc_is_register_i2c_driver();
966*4882a593Smuzhiyun 	if (ret < 0)
967*4882a593Smuzhiyun 		return ret;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	ret = platform_driver_register(&fimc_is_driver);
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	if (ret < 0)
972*4882a593Smuzhiyun 		fimc_is_unregister_i2c_driver();
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	return ret;
975*4882a593Smuzhiyun }
976*4882a593Smuzhiyun 
fimc_is_module_exit(void)977*4882a593Smuzhiyun static void fimc_is_module_exit(void)
978*4882a593Smuzhiyun {
979*4882a593Smuzhiyun 	fimc_is_unregister_i2c_driver();
980*4882a593Smuzhiyun 	platform_driver_unregister(&fimc_is_driver);
981*4882a593Smuzhiyun }
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun module_init(fimc_is_module_init);
984*4882a593Smuzhiyun module_exit(fimc_is_module_exit);
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun MODULE_ALIAS("platform:" FIMC_IS_DRV_NAME);
987*4882a593Smuzhiyun MODULE_AUTHOR("Younghwan Joo <yhwan.joo@samsung.com>");
988*4882a593Smuzhiyun MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
989*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
990