aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSandor Yu <R01008@freescale.com>2014-07-01 03:51:20 -0400
committerSandor Yu <R01008@freescale.com>2014-07-03 04:16:55 -0400
commit6193c09144f928d72b0474be28865489bb550cfe (patch)
tree99b410c6b59ab5e4f7ce63ed0f7c7c86a1376d30
parentafdee488043af1ca3568f3a7a69e0d4b019e92b4 (diff)
ENGR00317086-3 dcic: Add dcic driver source code
Add dcic driver source code. Support two instance dcic1 and dcic2. Signed-off-by: Sandor Yu <R01008@freescale.com> (cherry picked from commit 5dd90299f33e93252bd1cc7a9704adb9f469fa66)
-rw-r--r--arch/arm/configs/imx_v7_defconfig1
-rw-r--r--drivers/video/mxc/Kconfig6
-rw-r--r--drivers/video/mxc/Makefile1
-rw-r--r--drivers/video/mxc/mxc_dcic.c599
-rw-r--r--include/linux/mxc_dcic.h134
-rw-r--r--include/uapi/linux/mxc_dcic.h47
6 files changed, 788 insertions, 0 deletions
diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig
index ff1b66c9e1cd..9f4d52cf80ca 100644
--- a/arch/arm/configs/imx_v7_defconfig
+++ b/arch/arm/configs/imx_v7_defconfig
@@ -226,6 +226,7 @@ CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL=y
226CONFIG_FB_MXC_HDMI=y 226CONFIG_FB_MXC_HDMI=y
227CONFIG_FB_MXC_EINK_PANEL=y 227CONFIG_FB_MXC_EINK_PANEL=y
228CONFIG_FB_MXS_SII902X=y 228CONFIG_FB_MXS_SII902X=y
229CONFIG_FB_MXC_DCIC=m
229CONFIG_HANNSTAR_CABC=y 230CONFIG_HANNSTAR_CABC=y
230CONFIG_FRAMEBUFFER_CONSOLE=y 231CONFIG_FRAMEBUFFER_CONSOLE=y
231CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y 232CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
diff --git a/drivers/video/mxc/Kconfig b/drivers/video/mxc/Kconfig
index 7f2967f95afa..f0315bb21959 100644
--- a/drivers/video/mxc/Kconfig
+++ b/drivers/video/mxc/Kconfig
@@ -63,6 +63,12 @@ config FB_MXS_SII902X
63 tristate "Si Image SII9022 DVI/HDMI Interface Chip" 63 tristate "Si Image SII9022 DVI/HDMI Interface Chip"
64 depends on FB_MXS && I2C 64 depends on FB_MXS && I2C
65 65
66config FB_MXC_DCIC
67 tristate "MXC DCIC"
68 depends on FB_MXC_SYNC_PANEL
69 depends on MXC_IPU_V3 || FB_MXS
70 select VIDEOMODE_HELPERS
71
66config HANNSTAR_CABC 72config HANNSTAR_CABC
67 tristate "Hannstar CABC function" 73 tristate "Hannstar CABC function"
68 help 74 help
diff --git a/drivers/video/mxc/Makefile b/drivers/video/mxc/Makefile
index c0fec9e79727..3ce5dbbd7f15 100644
--- a/drivers/video/mxc/Makefile
+++ b/drivers/video/mxc/Makefile
@@ -6,4 +6,5 @@ obj-$(CONFIG_FB_MXC_EDID) += mxc_edid.o
6obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_dispdrv.o mxc_lcdif.o mxc_ipuv3_fb.o 6obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_dispdrv.o mxc_lcdif.o mxc_ipuv3_fb.o
7obj-$(CONFIG_FB_MXC_EINK_PANEL) += mxc_epdc_fb.o 7obj-$(CONFIG_FB_MXC_EINK_PANEL) += mxc_epdc_fb.o
8obj-$(CONFIG_FB_MXS_SII902X) += mxsfb_sii902x.o 8obj-$(CONFIG_FB_MXS_SII902X) += mxsfb_sii902x.o
9obj-$(CONFIG_FB_MXC_DCIC) += mxc_dcic.o
9obj-$(CONFIG_HANNSTAR_CABC) += hannstar_cabc.o 10obj-$(CONFIG_HANNSTAR_CABC) += hannstar_cabc.o
diff --git a/drivers/video/mxc/mxc_dcic.c b/drivers/video/mxc/mxc_dcic.c
new file mode 100644
index 000000000000..8cf909d5563d
--- /dev/null
+++ b/drivers/video/mxc/mxc_dcic.c
@@ -0,0 +1,599 @@
1/*
2 * Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved.
3 */
4
5/*
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20#include <linux/clk.h>
21#include <linux/cdev.h>
22#include <linux/delay.h>
23#include <linux/err.h>
24#include <linux/fs.h>
25#include <linux/fb.h>
26#include <linux/init.h>
27#include <linux/io.h>
28#include <linux/ioctl.h>
29#include <linux/interrupt.h>
30#include <linux/mfd/syscon.h>
31#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
32#include <linux/module.h>
33#include <linux/mxc_dcic.h>
34#include <linux/of_device.h>
35#include <linux/platform_device.h>
36#include <linux/regmap.h>
37#include <linux/types.h>
38#include <linux/uaccess.h>
39#include <video/videomode.h>
40#include <video/of_videomode.h>
41
42#define DRIVER_NAME "mxc_dcic"
43
44#define DCIC_IPU1_DI0 "dcic-ipu1-di0"
45#define DCIC_IPU1_DI1 "dcic-ipu1-di1"
46#define DCIC_IPU2_DI0 "dcic-ipu2-di0"
47#define DCIC_IPU2_DI1 "dcic-ipu2-di1"
48#define DCIC_LCDIF "dcic-lcdif"
49#define DCIC_LCDIF1 "dcic-lcdif1"
50#define DCIC_LCDIF2 "dcic-lcdif2"
51#define DCIC_LVDS "dcic-lvds"
52#define DCIC_LVDS0 "dcic-lvds0"
53#define DCIC_LVDS1 "dcic-lvds1"
54#define DCIC_HDMI "dcic-hdmi"
55
56#define DCIC0_DEV_NAME "mxc_dcic0"
57#define DCIC1_DEV_NAME "mxc_dcic1"
58
59#define FB_SYNC_OE_LOW_ACT 0x80000000
60#define FB_SYNC_CLK_LAT_FALL 0x40000000
61
62static const struct dcic_mux imx6q_dcic0_mux[] = {
63 {
64 .dcic = DCIC_IPU1_DI0,
65 .val = IMX6Q_GPR10_DCIC1_MUX_CTL_IPU1_DI0,
66 }, {
67 .dcic = DCIC_LVDS0,
68 .val = IMX6Q_GPR10_DCIC1_MUX_CTL_LVDS0,
69 }, {
70 .dcic = DCIC_LVDS1,
71 .val = IMX6Q_GPR10_DCIC1_MUX_CTL_LVDS1,
72 }, {
73 .dcic = DCIC_HDMI,
74 .val = IMX6Q_GPR10_DCIC1_MUX_CTL_HDMI,
75 }
76};
77
78static const struct dcic_mux imx6q_dcic1_mux[] = {
79 {
80 .dcic = DCIC_IPU1_DI1,
81 .val = IMX6Q_GPR10_DCIC2_MUX_CTL_IPU1_DI1,
82 }, {
83 .dcic = DCIC_LVDS0,
84 .val = IMX6Q_GPR10_DCIC2_MUX_CTL_LVDS0,
85 }, {
86 .dcic = DCIC_LVDS1,
87 .val = IMX6Q_GPR10_DCIC2_MUX_CTL_LVDS1,
88 }, {
89 .dcic = DCIC_HDMI,
90 .val = IMX6Q_GPR10_DCIC2_MUX_CTL_MIPI,
91 }
92};
93
94static const struct bus_mux imx6q_dcic_buses[] = {
95 {
96 .name = DCIC0_DEV_NAME,
97 .reg = IOMUXC_GPR10,
98 .shift = 0,
99 .mask = IMX6Q_GPR10_DCIC1_MUX_CTL_MASK,
100 .dcic_mux_num = ARRAY_SIZE(imx6q_dcic0_mux),
101 .dcics = imx6q_dcic0_mux,
102 }, {
103 .name = DCIC1_DEV_NAME,
104 .reg = IOMUXC_GPR10,
105 .shift = 2,
106 .mask = IMX6Q_GPR10_DCIC2_MUX_CTL_MASK,
107 .dcic_mux_num = ARRAY_SIZE(imx6q_dcic1_mux),
108 .dcics = imx6q_dcic1_mux,
109 }
110};
111
112static const struct dcic_info imx6q_dcic_info = {
113 .bus_mux_num = ARRAY_SIZE(imx6q_dcic_buses),
114 .buses = imx6q_dcic_buses,
115};
116
117static const struct dcic_mux imx6sx_dcic0_mux[] = {
118 {
119 .dcic = DCIC_LCDIF1,
120 .val = IMX6SX_GPR5_DISP_MUX_DCIC1_LCDIF1,
121 }, {
122 .dcic = DCIC_LVDS,
123 .val = IMX6SX_GPR5_DISP_MUX_DCIC1_LVDS,
124 }
125};
126
127static const struct dcic_mux imx6sx_dcic1_mux[] = {
128 {
129 .dcic = DCIC_LCDIF2,
130 .val = IMX6SX_GPR5_DISP_MUX_DCIC2_LCDIF2,
131 }, {
132 .dcic = DCIC_LVDS,
133 .val = IMX6SX_GPR5_DISP_MUX_DCIC2_LVDS,
134 }
135};
136
137static const struct bus_mux imx6sx_dcic_buses[] = {
138 {
139 .name = DCIC0_DEV_NAME,
140 .reg = IOMUXC_GPR5,
141 .shift = 1,
142 .mask = IMX6SX_GPR5_DISP_MUX_DCIC1_MASK,
143 .dcic_mux_num = ARRAY_SIZE(imx6sx_dcic0_mux),
144 .dcics = imx6sx_dcic0_mux,
145 }, {
146 .name = DCIC1_DEV_NAME,
147 .reg = IOMUXC_GPR5,
148 .shift = 2,
149 .mask = IMX6SX_GPR5_DISP_MUX_DCIC2_MASK,
150 .dcic_mux_num = ARRAY_SIZE(imx6sx_dcic1_mux),
151 .dcics = imx6sx_dcic1_mux,
152 }
153};
154
155static const struct dcic_info imx6sx_dcic_info = {
156 .bus_mux_num = ARRAY_SIZE(imx6sx_dcic_buses),
157 .buses = imx6sx_dcic_buses,
158};
159
160static const struct of_device_id dcic_dt_ids[] = {
161 { .compatible = "fsl,imx6q-dcic", .data = &imx6q_dcic_info, },
162 { .compatible = "fsl,imx6sx-dcic", .data = &imx6sx_dcic_info, },
163 { /* sentinel */ }
164};
165MODULE_DEVICE_TABLE(of, dcic_dt_ids);
166
167static int of_get_dcic_val(struct device_node *np, struct dcic_data *dcic)
168{
169 const char *mux;
170 int ret;
171 u32 i, dcic_id;
172
173 ret = of_property_read_string(np, "dcic_mux", &mux);
174 if (ret < 0) {
175 dev_err(dcic->dev, "Can not get dcic_mux\n");
176 return ret;
177 }
178 ret = of_property_read_u32(np, "dcic_id", &dcic_id);
179 if (ret < 0) {
180 dev_err(dcic->dev, "Can not get dcic_id\n");
181 return ret;
182 }
183
184 dcic->bus_n = dcic_id;
185
186 for (i = 0; i < dcic->buses[dcic_id].dcic_mux_num; i++)
187 if (!strcmp(mux, dcic->buses[dcic_id].dcics[i].dcic)) {
188 dcic->mux_n = i;
189 return dcic->buses[dcic_id].dcics[i].val;
190 }
191
192 return -EINVAL;
193}
194
195static void dcic_enable(struct dcic_data *dcic)
196{
197 u32 val;
198
199 val = readl(&dcic->regs->dcicc);
200 val |= DCICC_IC_ENABLE;
201 writel(val, &dcic->regs->dcicc);
202}
203
204void dcic_disable(struct dcic_data *dcic)
205{
206 u32 val;
207
208 val = readl(&dcic->regs->dcicc);
209 val &= ~DCICC_IC_MASK;
210 val |= DCICC_IC_DISABLE;
211 writel(val, &dcic->regs->dcicc);
212}
213
214static void roi_enable(struct dcic_data *dcic, struct roi_params *roi_param)
215{
216 u32 val;
217 u32 roi_n = roi_param->roi_n;
218
219 val = readl(&dcic->regs->ROI[roi_n].dcicrc);
220 val |= DCICRC_ROI_ENABLE;
221 if (roi_param->freeze)
222 val |= DCICRC_ROI_FROZEN;
223 writel(val, &dcic->regs->ROI[roi_n].dcicrc);
224}
225
226static void roi_disable(struct dcic_data *dcic, u32 roi_n)
227{
228 u32 val;
229
230 val = readl(&dcic->regs->ROI[roi_n].dcicrc);
231 val &= ~DCICRC_ROI_ENABLE;
232 writel(val, &dcic->regs->ROI[roi_n].dcicrc);
233}
234
235static bool roi_configure(struct dcic_data *dcic, struct roi_params *roi_param)
236{
237 struct roi_regs *roi_reg;
238 u32 val;
239
240 if (roi_param->roi_n < 0 || roi_param->roi_n >= 16) {
241 printk(KERN_ERR "Error, Wrong ROI number %d\n", roi_param->roi_n);
242 return false;
243 }
244
245 if (roi_param->end_x <= roi_param->start_x ||
246 roi_param->end_y <= roi_param->start_y) {
247 printk(KERN_ERR "Error, Wrong ROI\n");
248 return false;
249 }
250
251 roi_reg = (struct roi_regs *) &dcic->regs->ROI[roi_param->roi_n];
252
253 /* init roi block size */
254 val = roi_param->start_y << 16 | roi_param->start_x;
255 writel(val, &roi_reg->dcicrc);
256
257 val = roi_param->end_y << 16 | roi_param->end_x;
258 writel(val, &roi_reg->dcicrs);
259
260 writel(roi_param->ref_sig, &roi_reg->dcicrrs);
261
262 roi_enable(dcic, roi_param);
263 return true;
264}
265
266static void dcic_int_enable(struct dcic_data *dcic)
267{
268 u32 val;
269
270 /* Clean pending interrupt before enable int */
271 writel(DCICS_FI_STAT_PENDING, &dcic->regs->dcics);
272 writel(0xffffffff, &dcic->regs->dcics);
273
274 /* Enable function interrupt */
275 val = readl(&dcic->regs->dcicic);
276 val &= ~DCICIC_FUN_INT_MASK;
277 val |= DCICIC_FUN_INT_ENABLE;
278 writel(val, &dcic->regs->dcicic);
279}
280
281static void dcic_int_disable(struct dcic_data *dcic)
282{
283 u32 val;
284
285 /* Disable both function and error interrupt */
286 val = readl(&dcic->regs->dcicic);
287 val = DCICIC_ERROR_INT_DISABLE | DCICIC_FUN_INT_DISABLE;
288 writel(val, &dcic->regs->dcicic);
289}
290
291static irqreturn_t dcic_irq_handler(int irq, void *data)
292{
293 u32 i;
294
295 struct dcic_data *dcic = data;
296 u32 dcics = readl(&dcic->regs->dcics);
297
298 dcic->result = dcics & 0xffff;
299
300 dcic_int_disable(dcic);
301
302 /* clean dcic interrupt state */
303 writel(DCICS_FI_STAT_PENDING, &dcic->regs->dcics);
304 writel(dcics, &dcic->regs->dcics);
305
306 for (i = 0; i < 16; i++) {
307 printk(KERN_INFO "ROI=%d,crcRS=0x%x, crcCS=0x%x\n", i,
308 readl(&dcic->regs->ROI[i].dcicrrs),
309 readl(&dcic->regs->ROI[i].dcicrcs));
310 }
311 complete(&dcic->roi_crc_comp);
312
313 return 0;
314}
315
316static int dcic_configure(struct dcic_data *dcic, unsigned int sync)
317{
318 u32 val;
319 val = 0;
320
321 /* vsync, hsync, DE, clk_pol */
322 if (!(sync & FB_SYNC_HOR_HIGH_ACT))
323 val |= DCICC_HSYNC_POL_ACTIVE_LOW;
324 if (!(sync & FB_SYNC_VERT_HIGH_ACT))
325 val |= DCICC_VSYNC_POL_ACTIVE_LOW;
326 if (sync & FB_SYNC_OE_LOW_ACT)
327 val |= DCICC_DE_ACTIVE_LOW;
328 if (sync & FB_SYNC_CLK_LAT_FALL)
329 val |= DCICC_CLK_POL_INVERTED;
330
331 writel(val, &dcic->regs->dcicc);
332 return 0;
333}
334
335static int dcic_open(struct inode *inode, struct file *file)
336{
337 struct dcic_data *dcic;
338
339 dcic = container_of(inode->i_cdev, struct dcic_data, cdev);
340
341 mutex_lock(&dcic->lock);
342
343 clk_prepare_enable(dcic->disp_axi_clk);
344 clk_prepare_enable(dcic->dcic_clk);
345
346 file->private_data = dcic;
347 mutex_unlock(&dcic->lock);
348 return 0;
349}
350
351static int dcic_release(struct inode *inode, struct file *file)
352{
353 struct dcic_data *dcic = file->private_data;
354 u32 i;
355
356 mutex_lock(&dcic->lock);
357
358 for (i = 0; i < 16; i++)
359 roi_disable(dcic, i);
360
361 clk_disable_unprepare(dcic->dcic_clk);
362 clk_disable_unprepare(dcic->disp_axi_clk);
363
364 mutex_unlock(&dcic->lock);
365 return 0;
366}
367
368static int dcic_init(struct device_node *np, struct dcic_data *dcic)
369{
370 u32 val, bus;
371
372 val = of_get_dcic_val(np, dcic);
373 if (val < 0) {
374 printk(KERN_ERR "Error incorrect\n");
375 return -1;
376 }
377
378 bus = dcic->bus_n;
379
380 regmap_update_bits(dcic->regmap, dcic->buses[bus].reg ,
381 dcic->buses[bus].mask, val);
382
383 return 0;
384}
385
386static long dcic_ioctl(struct file *file,
387 unsigned int cmd, unsigned long arg)
388{
389 int __user *argp = (void __user *)arg;
390 struct dcic_data *dcic = file->private_data;
391 struct roi_params roi_param;
392 unsigned int sync;
393 int ret = 0;
394
395 switch (cmd) {
396 case DCIC_IOC_CONFIG_DCIC:
397 if (!copy_from_user(&sync, argp, sizeof(unsigned int)))
398 dcic_configure(dcic, sync);
399 break;
400 case DCIC_IOC_CONFIG_ROI:
401 if (copy_from_user(&roi_param, argp, sizeof(roi_param)))
402 return -EFAULT;
403 else
404 if (!roi_configure(dcic, &roi_param))
405 return -EINVAL;
406 break;
407 case DCIC_IOC_GET_RESULT:
408 init_completion(&dcic->roi_crc_comp);
409
410 dcic_enable(dcic);
411
412 dcic->result = 0;
413 msleep(25);
414
415 dcic_int_enable(dcic);
416
417 ret = wait_for_completion_interruptible_timeout(
418 &dcic->roi_crc_comp, 1 * HZ);
419 if (ret == 0) {
420 dev_err(dcic->dev,
421 "dcic wait for roi crc cal timeout\n");
422 ret = -ETIME;
423 } else if (ret > 0) {
424 if (copy_to_user(argp, &dcic->result, sizeof(dcic->result)))
425 return -EFAULT;
426 ret = 0;
427 }
428 dcic_disable(dcic);
429 break;
430 default:
431 printk(KERN_ERR "%s, Unsupport cmd %d\n", __func__, cmd);
432 break;
433 }
434 return ret;
435}
436
437
438static const struct file_operations mxc_dcic_fops = {
439 .owner = THIS_MODULE,
440 .open = dcic_open,
441 .release = dcic_release,
442 .unlocked_ioctl = dcic_ioctl,
443};
444
445static int dcic_probe(struct platform_device *pdev)
446{
447 struct device *dev = &pdev->dev;
448 const struct of_device_id *of_id =
449 of_match_device(dcic_dt_ids, dev);
450 const struct dcic_info *dcic_info =
451 (const struct dcic_info *)of_id->data;
452 struct device_node *np = dev->of_node;
453 struct dcic_data *dcic;
454 struct resource *res;
455 const char *name;
456 dev_t devt;
457 int ret = 0;
458 int irq;
459
460 dcic = devm_kzalloc(&pdev->dev,
461 sizeof(struct dcic_data),
462 GFP_KERNEL);
463 if (!dcic) {
464 dev_err(&pdev->dev, "Cannot allocate device data\n");
465 ret = -ENOMEM;
466 goto ealloc;
467 }
468
469 platform_set_drvdata(pdev, dcic);
470
471 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
472 if (!res) {
473 dev_err(&pdev->dev, "No dcic base address found.\n");
474 ret = -ENODEV;
475 goto ealloc;
476 }
477
478 dcic->regs = (struct dcic_regs *) devm_ioremap(&pdev->dev, res->start, resource_size(res));
479 if (!dcic->regs) {
480 dev_err(&pdev->dev, "ioremap failed with dcic base\n");
481 ret = -ENOMEM;
482 goto ealloc;
483 }
484
485 dcic->dev = dev;
486 dcic->buses = dcic_info->buses;
487
488 dcic->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
489 if (IS_ERR(dcic->regmap)) {
490 dev_err(dev, "failed to get parent regmap\n");
491 ret = PTR_ERR(dcic->regmap);
492 goto ealloc;
493 }
494
495 /* clock */
496 dcic->disp_axi_clk = devm_clk_get(&pdev->dev, "disp-axi");
497 if (IS_ERR(dcic->disp_axi_clk)) {
498 dev_err(&pdev->dev, "get disp-axi clock failed\n");
499 ret = PTR_ERR(dcic->disp_axi_clk);
500 goto ealloc;
501 }
502
503 dcic->dcic_clk = devm_clk_get(&pdev->dev, "dcic");
504 if (IS_ERR(dcic->dcic_clk)) {
505 dev_err(&pdev->dev, "get dcic clk failed\n");
506 ret = PTR_ERR(dcic->dcic_clk);
507 goto ealloc;
508 }
509
510 mutex_init(&dcic->lock);
511 ret = dcic_init(np, dcic);
512 if (ret < 0) {
513 printk(KERN_ERR "Failed init dcic\n");
514 goto ealloc;
515 }
516
517 /* register device */
518 name = dcic->buses[dcic->bus_n].name;
519 dcic->major = register_chrdev(0, name, &mxc_dcic_fops);
520 if (dcic->major < 0) {
521 printk(KERN_ERR "DCIC: unable to get a major for dcic\n");
522 ret = -EBUSY;
523 goto ealloc;
524 }
525
526 dcic->class = class_create(THIS_MODULE, name);
527 if (IS_ERR(dcic->class)) {
528 ret = PTR_ERR(dcic->class);
529 goto err_out_chrdev;
530 }
531
532 /* create char device */
533 devt = MKDEV(dcic->major, 0);
534 dcic->devt = devt;
535
536 cdev_init(&dcic->cdev, &mxc_dcic_fops);
537 dcic->cdev.owner = THIS_MODULE;
538 ret = cdev_add(&dcic->cdev, devt, 1);
539 if (ret)
540 goto err_out_class;
541
542 device_create(dcic->class, NULL, devt,
543 NULL, name);
544
545 /* IRQ */
546 irq = platform_get_irq(pdev, 0);
547
548 ret = devm_request_irq(&pdev->dev, irq, dcic_irq_handler, 0,
549 dev_name(&pdev->dev), dcic);
550 if (ret) {
551 dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n",
552 irq, ret);
553 goto err_out_cdev;
554 }
555
556 return 0;
557
558err_out_cdev:
559 cdev_del(&dcic->cdev);
560err_out_class:
561 device_destroy(dcic->class, devt);
562 class_destroy(dcic->class);
563err_out_chrdev:
564 unregister_chrdev(dcic->major, name);
565ealloc:
566 return ret;
567}
568
569static int dcic_remove(struct platform_device *pdev)
570{
571 struct dcic_data *dcic = platform_get_drvdata(pdev);
572 const char *name;
573
574 name = dcic->buses[dcic->bus_n].name;
575
576 device_destroy(dcic->class, dcic->devt);
577 cdev_del(&dcic->cdev);
578 class_destroy(dcic->class);
579 unregister_chrdev(dcic->major, name);
580 mutex_destroy(&dcic->lock);
581
582 return 0;
583}
584
585static struct platform_driver dcic_driver = {
586 .driver = {
587 .name = DRIVER_NAME,
588 .of_match_table = dcic_dt_ids,
589 },
590 .probe = dcic_probe,
591 .remove = dcic_remove,
592};
593
594module_platform_driver(dcic_driver);
595
596MODULE_AUTHOR("Freescale Semiconductor, Inc.");
597MODULE_DESCRIPTION("MXC DCIC driver");
598MODULE_LICENSE("GPL");
599MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/include/linux/mxc_dcic.h b/include/linux/mxc_dcic.h
new file mode 100644
index 000000000000..9f0ebc57bd60
--- /dev/null
+++ b/include/linux/mxc_dcic.h
@@ -0,0 +1,134 @@
1/*
2 * Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved
3 */
4
5/*
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21/*!
22 * @file linux/mxc_dcic.h
23 *
24 * @brief Global header file for the MXC DCIC driver
25 *
26 * @ingroup MXC DCIC
27 */
28
29#ifndef __LINUX_DCIC_H__
30#define __LINUX_DCIC_H__
31
32#include <uapi/linux/mxc_dcic.h>
33
34#define DCICC_IC_ENABLE 0x1
35#define DCICC_IC_DISABLE 0x0
36#define DCICC_IC_MASK 0x1
37#define DCICC_DE_ACTIVE_HIGH 0
38#define DCICC_DE_ACTIVE_LOW (0x1 << 4)
39#define DCICC_DE_ACTIVE_MASK (0x1 << 4)
40#define DCICC_HSYNC_POL_ACTIVE_HIGH 0
41#define DCICC_HSYNC_POL_ACTIVE_LOW (0x1 << 5)
42#define DCICC_HSYNC_POL_ACTIVE_MASK (0x1 << 5)
43#define DCICC_VSYNC_POL_ACTIVE_HIGH 0
44#define DCICC_VSYNC_POL_ACTIVE_LOW (0x1 << 6)
45#define DCICC_VSYNC_POL_ACTIVE_MASK (0x1 << 6)
46#define DCICC_CLK_POL_NO_INVERTED 0
47#define DCICC_CLK_POL_INVERTED (0x1 << 7)
48#define DCICC_CLK_POL_INVERTED_MASK (0x1 << 7)
49
50#define DCICIC_ERROR_INT_DISABLE 1
51#define DCICIC_ERROR_INT_ENABLE 0
52#define DCICIC_ERROR_INT_MASK_MASK 1
53#define DCICIC_FUN_INT_DISABLE (0x1 << 1)
54#define DCICIC_FUN_INT_ENABLE 0
55#define DCICIC_FUN_INT_MASK (0x1 << 1)
56#define DCICIC_FREEZE_MASK_CHANGED 0
57#define DCICIC_FREEZE_MASK_FORZEN (0x1 << 3)
58#define DCICIC_FREEZE_MASK_MASK (0x1 << 3)
59#define DCICIC_EXT_SIG_EX_DISABLE 0
60#define DCICIC_EXT_SIG_EN_ENABLE (0x1 << 16)
61#define DCICIC_EXT_SIG_EN_MASK (0x1 << 16)
62
63#define DCICS_ROI_MATCH_STAT_MASK 0xFFFF
64#define DCICS_EI_STAT_PENDING (0x1 << 16)
65#define DCICS_EI_STAT_NO_PENDING 0
66#define DCICS_FI_STAT_PENDING (0x1 << 17)
67#define DCICS_FI_STAT_NO_PENDING 0
68
69#define DCICRC_ROI_START_OFFSET_X_MASK 0x1FFF
70#define DCICRC_ROI_START_OFFSET_X_SHIFT 0
71#define DCICRC_ROI_START_OFFSET_Y_MASK (0xFFF << 16)
72#define DCICRC_ROI_START_OFFSET_Y_SHIFT 16
73#define DCICRC_ROI_CHANGED 0
74#define DCICRC_ROI_FROZEN (0x1 << 30)
75#define DCICRC_ROI_ENABLE (0x1 << 31)
76#define DCICRC_ROI_DISABLE 0
77
78#define DCICRS_ROI_END_OFFSET_X_MASK 0x1FFF
79#define DCICRS_ROI_END_OFFSET_X_SHIFT 0
80#define DCICRS_ROI_END_OFFSET_Y_MASK (0xFFF << 16)
81#define DCICRS_ROI_END_OFFSET_Y_SHIFT 16
82
83struct roi_regs {
84 u32 dcicrc;
85 u32 dcicrs;
86 u32 dcicrrs;
87 u32 dcicrcs;
88};
89
90struct dcic_regs {
91 u32 dcicc;
92 u32 dcicic;
93 u32 dcics;
94 u32 dcic_reserved;
95 struct roi_regs ROI[16];
96};
97
98struct dcic_mux {
99 char dcic[16];
100 u32 val;
101};
102
103struct bus_mux {
104 char name[16];
105 int reg;
106 int shift;
107 int mask;
108 int dcic_mux_num;
109 const struct dcic_mux *dcics;
110};
111
112struct dcic_info {
113 int bus_mux_num;
114 const struct bus_mux *buses;
115};
116
117struct dcic_data {
118 struct regmap *regmap;
119 struct device *dev;
120 struct dcic_regs *regs;
121 const struct bus_mux *buses;
122 u32 bus_n;
123 u32 mux_n;
124 struct clk *disp_axi_clk;
125 struct clk *dcic_clk;
126 struct mutex lock;
127 struct completion roi_crc_comp;
128 struct class *class;
129 int major;
130 struct cdev cdev; /* Char device structure */
131 dev_t devt;
132 unsigned int result;
133};
134#endif
diff --git a/include/uapi/linux/mxc_dcic.h b/include/uapi/linux/mxc_dcic.h
new file mode 100644
index 000000000000..cbcacaa64b3c
--- /dev/null
+++ b/include/uapi/linux/mxc_dcic.h
@@ -0,0 +1,47 @@
1/*
2 * Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved
3 */
4
5/*
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21/*!
22 * @file uapi/linux/mxc_dcic.h
23 *
24 * @brief MXC DCIC private header file
25 *
26 * @ingroup MXC DCIC
27 */
28#ifndef __ASM_ARCH_MXC_DCIC_H__
29#define __ASM_ARCH_MXC_DCIC_H__
30
31#define DCIC_IOC_ALLOC_ROI_NUM _IO('D', 10)
32#define DCIC_IOC_FREE_ROI_NUM _IO('D', 11)
33#define DCIC_IOC_CONFIG_DCIC _IO('D', 12)
34#define DCIC_IOC_CONFIG_ROI _IO('D', 13)
35#define DCIC_IOC_GET_RESULT _IO('D', 14)
36
37struct roi_params {
38 unsigned int roi_n;
39 unsigned int ref_sig;
40 unsigned int start_y;
41 unsigned int start_x;
42 unsigned int end_y;
43 unsigned int end_x;
44 char freeze;
45};
46
47#endif