[Meego-kernel] [MFLD Camera - PATCH v3 3/9] ISP v4l2 driver based on v4l2 API and framework implemenation on MFLD platform.
Zhang, Xiaolin
xiaolin.zhang at intel.com
Wed Dec 1 10:52:17 PST 2010
>From 95425dd8183b036664937fbb2110dda2537afbe3 Mon Sep 17 00:00:00 2001
From: Xiaolin Zhang <xiaolin.zhang at intel.com>
Date: Wed, 1 Dec 2010 21:41:39 +0800
Subject: [MFLD Camera - PATCH v3 3/9] ISP v4l2 driver based on v4l2 API and framework implemenation on MFLD platform.
Signed-off-by: Xiaolin Zhang <xiaolin.zhang at intel.com>
---
.../mfld_ci/mfldisp/include/mfldisp/ispparam.h | 354 ++
.../mfldisp/include/mfldisp/mfldisp_internal.h | 134 +
.../mfldisp/include/mfldisp/mfldisp_sensor.h | 67 +
.../mfld_ci/mfldisp/include/mfldisp/mfldisp_v4l2.h | 239 ++
drivers/media/video/mfld_ci/mfldisp/mfldisp_v4l2.c | 4335 ++++++++++++++++++++
5 files changed, 5129 insertions(+), 0 deletions(-)
create mode 100644 drivers/media/video/mfld_ci/mfldisp/include/mfldisp/ispparam.h
create mode 100644 drivers/media/video/mfld_ci/mfldisp/include/mfldisp/mfldisp_internal.h
create mode 100644 drivers/media/video/mfld_ci/mfldisp/include/mfldisp/mfldisp_sensor.h
create mode 100644 drivers/media/video/mfld_ci/mfldisp/include/mfldisp/mfldisp_v4l2.h
create mode 100644 drivers/media/video/mfld_ci/mfldisp/mfldisp_v4l2.c
diff --git a/drivers/media/video/mfld_ci/mfldisp/include/mfldisp/ispparam.h b/drivers/media/video/mfld_ci/mfldisp/include/mfldisp/ispparam.h
new file mode 100644
index 0000000..fb077e6
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/include/mfldisp/ispparam.h
@@ -0,0 +1,354 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+/*
+ * structure for handling ISP parameters,
+ *
+ * this structure will shared both in kernel/user space
+ */
+#ifndef ISP_PARAM_H_
+#define ISP_PARAM_H_
+
+unsigned short default_gamma_table[sh_css_gamma_table_size] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16,
+ 17, 18, 19, 20, 21, 23, 24, 25, 27, 28, 29, 31, 32, 33, 35, 36,
+ 38, 39, 41, 42, 44, 45, 47, 48, 49, 51, 52, 54, 55, 57, 58, 60,
+ 61, 62, 64, 65, 66, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 93, 94,
+ 95, 96, 97, 98, 98, 99, 100, 101, 102, 102, 103, 104, 105, 105, 106,
+ 107,
+ 108, 108, 109, 110, 110, 111, 112, 112, 113, 114, 114, 115, 116, 116,
+ 117, 118,
+ 118, 119, 120, 120, 121, 121, 122, 123, 123, 124, 125, 125, 126, 126,
+ 127, 127, /* 128 */
+ 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 134, 134, 135, 135,
+ 136, 136,
+ 137, 137, 138, 138, 139, 139, 140, 140, 141, 141, 142, 142, 143, 143,
+ 144, 144,
+ 145, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149, 150, 150, 150,
+ 151, 151,
+ 152, 152, 152, 153, 153, 154, 154, 155, 155, 155, 156, 156, 156, 157,
+ 157, 158,
+ 158, 158, 159, 159, 160, 160, 160, 161, 161, 161, 162, 162, 162, 163,
+ 163, 163,
+ 164, 164, 164, 165, 165, 165, 166, 166, 166, 167, 167, 167, 168, 168,
+ 168, 169,
+ 169, 169, 170, 170, 170, 170, 171, 171, 171, 172, 172, 172, 172, 173,
+ 173, 173,
+ 174, 174, 174, 174, 175, 175, 175, 176, 176, 176, 176, 177, 177, 177,
+ 177, 178, /* 256 */
+ 178, 178, 178, 179, 179, 179, 179, 180, 180, 180, 180, 181, 181, 181,
+ 181, 182,
+ 182, 182, 182, 182, 183, 183, 183, 183, 184, 184, 184, 184, 184, 185,
+ 185, 185,
+ 185, 186, 186, 186, 186, 186, 187, 187, 187, 187, 187, 188, 188, 188,
+ 188, 188,
+ 189, 189, 189, 189, 189, 190, 190, 190, 190, 190, 191, 191, 191, 191,
+ 191, 192,
+ 192, 192, 192, 192, 192, 193, 193, 193, 193, 193, 194, 194, 194, 194,
+ 194, 194,
+ 195, 195, 195, 195, 195, 195, 196, 196, 196, 196, 196, 196, 197, 197,
+ 197, 197,
+ 197, 197, 198, 198, 198, 198, 198, 198, 198, 199, 199, 199, 199, 199,
+ 199, 200,
+ 200, 200, 200, 200, 200, 200, 201, 201, 201, 201, 201, 201, 201, 202,
+ 202, 202, /* 384 */
+ 202, 202, 202, 202, 203, 203, 203, 203, 203, 203, 203, 204, 204, 204,
+ 204, 204,
+ 204, 204, 204, 205, 205, 205, 205, 205, 205, 205, 205, 206, 206, 206,
+ 206, 206,
+ 206, 206, 206, 207, 207, 207, 207, 207, 207, 207, 207, 208, 208, 208,
+ 208, 208,
+ 208, 208, 208, 209, 209, 209, 209, 209, 209, 209, 209, 209, 210, 210,
+ 210, 210,
+ 210, 210, 210, 210, 210, 211, 211, 211, 211, 211, 211, 211, 211, 211,
+ 212, 212,
+ 212, 212, 212, 212, 212, 212, 212, 213, 213, 213, 213, 213, 213, 213,
+ 213, 213,
+ 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 215, 215, 215, 215,
+ 215, 215,
+ 215, 215, 215, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 217,
+ 217, 217, /* 512 */
+ 217, 217, 217, 217, 217, 217, 217, 218, 218, 218, 218, 218, 218, 218,
+ 218, 218,
+ 218, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 220, 220, 220,
+ 220, 220,
+ 220, 220, 220, 220, 220, 221, 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221,
+ 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 223, 223, 223, 223,
+ 223, 223,
+ 223, 223, 223, 223, 223, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224,
+ 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 226, 226,
+ 226, 226,
+ 226, 226, 226, 226, 226, 226, 226, 227, 227, 227, 227, 227, 227, 227,
+ 227, 227,
+ 227, 227, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228,
+ 229, 229,
+ 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230, 230,
+ 230, 230,
+ 230, 230, 230, 230, 230, 230, 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231,
+ 231, 231, 231, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 233,
+ 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 234, 234,
+ 234, 234,
+ 234, 234, 234, 234, 234, 234, 234, 234, 234, 235, 235, 235, 235, 235,
+ 235, 235,
+ 235, 235, 235, 235, 235, 235, 236, 236, 236, 236, 236, 236, 236, 236,
+ 236, 236,
+ 236, 236, 236, 236, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237,
+ 237, 237,
+ 237, 237, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238,
+ 238, 238,
+ 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239,
+ 240, 240,
+ 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 241, 241,
+ 241, 241,
+ 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 242, 242, 242,
+ 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243,
+ 243, 243,
+ 243, 243, 243, 243, 243, 243, 243, 243, 243, 244, 244, 244, 244, 244,
+ 244, 244,
+ 244, 244, 244, 244, 244, 244, 244, 244, 245, 245, 245, 245, 245, 245,
+ 245, 245,
+ 245, 245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246,
+ 246, 246,
+ 246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 247, 247, 247,
+ 247, 247,
+ 247, 247, 247, 247, 247, 247, 247, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 249, 249, 249,
+ 249, 249,
+ 249, 249, 249, 249, 249, 249, 249, 250, 250, 250, 250, 250, 250, 250,
+ 250, 250,
+ 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251, 251,
+ 251, 251,
+ 251, 251, 251, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 252,
+ 252, 252,
+ 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253,
+ 253, 253,
+ 253, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254,
+ 254, 254,
+ 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255,
+ 255, 255
+};
+
+unsigned short default_ctc_table[sh_css_ctc_table_size] = {
+ 0, 0, 256, 384, 384, 497, 765, 806, 837, 851, 888, 901, 957, 981, 993,
+ 1001,
+ 1011, 1029, 1028, 1039, 1062, 1059, 1073, 1080, 1083, 1085, 1085, 1098,
+ 1080, 1084, 1085, 1093,
+ 1078, 1073, 1070, 1069, 1077, 1066, 1072, 1063, 1053, 1044, 1046, 1053,
+ 1039, 1028, 1025, 1024,
+ 1012, 1013, 1016, 996, 992, 990, 990, 980, 969, 968, 961, 955, 951, 949,
+ 933, 930,
+ 929, 925, 921, 916, 906, 901, 895, 893, 886, 877, 872, 869, 866, 861,
+ 857, 849,
+ 845, 838, 836, 832, 823, 821, 815, 813, 809, 805, 796, 793, 790, 785,
+ 784, 778,
+ 772, 768, 766, 763, 758, 752, 749, 745, 741, 740, 736, 730, 726, 724,
+ 723, 718,
+ 711, 709, 706, 704, 701, 698, 691, 689, 688, 683, 683, 678, 675, 673,
+ 671, 669,
+ 666, 663, 661, 660, 656, 656, 653, 650, 648, 647, 646, 643, 639, 638,
+ 637, 635,
+ 633, 632, 629, 627, 626, 625, 622, 621, 618, 618, 614, 614, 612, 609,
+ 606, 606,
+ 603, 600, 600, 597, 594, 591, 590, 586, 582, 581, 578, 575, 572, 569,
+ 563, 560,
+ 557, 554, 551, 548, 545, 539, 536, 533, 529, 527, 524, 519, 516, 513,
+ 510, 507,
+ 504, 501, 498, 493, 491, 488, 485, 484, 480, 476, 474, 471, 467, 466,
+ 464, 460,
+ 459, 455, 453, 449, 447, 446, 443, 441, 438, 435, 432, 432, 429, 427,
+ 426, 422,
+ 419, 418, 416, 414, 412, 410, 408, 406, 404, 402, 401, 398, 397, 395,
+ 393, 390,
+ 389, 388, 387, 384, 382, 380, 378, 377, 376, 375, 372, 370, 368, 368,
+ 366, 364,
+ 363, 361, 360, 358, 357, 355, 354, 352, 351, 350, 349, 346, 345, 344,
+ 344, 342,
+ 340, 339, 337, 337, 336, 335, 333, 331, 330, 329, 328, 326, 326, 324,
+ 324, 322,
+ 321, 320, 318, 318, 318, 317, 315, 313, 312, 311, 311, 310, 308, 307,
+ 306, 306,
+ 304, 304, 302, 301, 300, 300, 299, 297, 297, 296, 296, 294, 294, 292,
+ 291, 291,
+ 291, 290, 288, 287, 286, 286, 287, 285, 284, 283, 282, 282, 281, 281,
+ 279, 278,
+ 278, 278, 276, 276, 275, 274, 274, 273, 271, 270, 269, 268, 268, 267,
+ 265, 262,
+ 261, 260, 260, 259, 257, 254, 252, 252, 251, 251, 249, 246, 245, 244,
+ 243, 242,
+ 240, 239, 239, 237, 235, 235, 233, 231, 232, 230, 229, 226, 225, 224,
+ 225, 224,
+ 223, 220, 219, 219, 218, 217, 217, 214, 213, 213, 212, 211, 209, 209,
+ 209, 208,
+ 206, 205, 204, 203, 204, 203, 201, 200, 199, 197, 198, 198, 197, 195,
+ 194, 194,
+ 193, 192, 192, 191, 189, 190, 189, 188, 186, 187, 186, 185, 185, 184,
+ 183, 181,
+ 183, 182, 181, 180, 179, 178, 178, 178, 177, 176, 175, 176, 175, 174,
+ 174, 173,
+ 172, 173, 172, 171, 170, 170, 169, 169, 169, 168, 167, 166, 167, 167,
+ 166, 165,
+ 164, 164, 164, 163, 164, 163, 162, 163, 162, 161, 160, 161, 160, 160,
+ 160, 159,
+ 158, 157, 158, 158, 157, 157, 156, 156, 156, 156, 155, 155, 154, 154,
+ 154, 154,
+ 154, 153, 152, 153, 152, 152, 151, 152, 151, 152, 151, 150, 150, 149,
+ 149, 150,
+ 149, 149, 148, 148, 148, 149, 148, 147, 146, 146, 147, 146, 147, 146,
+ 145, 146,
+ 146, 145, 144, 145, 144, 145, 144, 144, 143, 143, 143, 144, 143, 142,
+ 142, 142,
+ 142, 142, 142, 141, 141, 141, 141, 140, 140, 141, 140, 140, 141, 140,
+ 139, 139,
+ 139, 140, 139, 139, 138, 138, 137, 139, 138, 138, 138, 137, 138, 137,
+ 137, 137,
+ 137, 136, 137, 136, 136, 136, 136, 135, 136, 135, 135, 135, 135, 136,
+ 135, 135,
+ 134, 134, 133, 135, 134, 134, 134, 133, 134, 133, 134, 133, 133, 132,
+ 133, 133,
+ 132, 133, 132, 132, 132, 132, 131, 131, 131, 132, 131, 131, 130, 131,
+ 130, 132,
+ 131, 130, 130, 129, 130, 129, 130, 129, 129, 129, 130, 129, 128, 128,
+ 128, 128,
+ 129, 128, 128, 127, 127, 128, 128, 127, 127, 126, 126, 127, 127, 126,
+ 126, 126,
+ 127, 126, 126, 126, 125, 125, 126, 125, 125, 124, 124, 124, 125, 125,
+ 124, 124,
+ 123, 124, 124, 123, 123, 122, 122, 122, 122, 122, 121, 120, 120, 119,
+ 118, 118,
+ 118, 117, 117, 116, 115, 115, 115, 114, 114, 113, 113, 112, 111, 111,
+ 111, 110,
+ 110, 109, 109, 108, 108, 108, 107, 107, 106, 106, 105, 105, 105, 104,
+ 104, 103,
+ 103, 102, 102, 102, 102, 101, 101, 100, 100, 99, 99, 99, 99, 99, 99, 98,
+ 97, 98, 97, 97, 97, 96, 96, 95, 96, 95, 96, 95, 95, 94, 94, 95,
+ 94, 94, 94, 93, 93, 92, 93, 93, 93, 93, 92, 92, 91, 92, 92, 92,
+ 91, 91, 90, 90, 91, 91, 91, 90, 90, 90, 90, 91, 90, 90, 90, 89,
+ 89, 89, 90, 89, 89, 89, 89, 89, 88, 89, 89, 88, 88, 88, 88, 87,
+ 89, 88, 88, 88, 88, 88, 87, 88, 88, 88, 87, 87, 87, 87, 87, 88,
+ 87, 87, 87, 87, 87, 87, 88, 87, 87, 87, 87, 86, 86, 87, 87, 87,
+ 87, 86, 86, 86, 87, 87, 86, 87, 86, 86, 86, 87, 87, 86, 86, 86,
+ 86, 86, 87, 87, 86, 85, 85, 85, 84, 85, 85, 84, 84, 83, 83, 82,
+ 82, 82, 81, 81, 80, 79, 79, 79, 78, 77, 77, 76, 76, 76, 75, 74,
+ 74, 74, 73, 73, 72, 71, 71, 71, 70, 70, 69, 69, 68, 68, 67, 67,
+ 67, 66, 66, 65, 65, 64, 64, 63, 62, 62, 62, 61, 60, 60, 59, 59,
+ 58, 58, 57, 57, 56, 56, 56, 55, 55, 54, 55, 55, 54, 53, 53, 52,
+ 53, 53, 52, 51, 51, 50, 51, 50, 49, 49, 50, 49, 49, 48, 48, 47,
+ 47, 48, 46, 45, 45, 45, 46, 45, 45, 44, 45, 45, 45, 43, 42, 42,
+ 41, 43, 41, 40, 40, 39, 40, 41, 39, 39, 39, 39, 39, 38, 35, 35,
+ 34, 37, 36, 34, 33, 33, 33, 35, 34, 32, 32, 31, 32, 30, 29, 26,
+ 25, 25, 27, 26, 23, 23, 23, 25, 24, 24, 22, 21, 20, 19, 16, 14,
+ 13, 13, 13, 10, 9, 7, 7, 7, 12, 12, 12, 7, 0, 0, 0, 0
+};
+
+/* multiple axis color correction table, 64values = 2x2matrix
+ * for 16area, 1value per 16bit */
+const short default_macc_table[sh_css_num_macc_axes * 4] = {
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256,
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256,
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256,
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256
+};
+
+const short blue_macc_table[sh_css_num_macc_axes * 4] = {
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256,
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256,
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256,
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256
+};
+
+const short green_macc_table[sh_css_num_macc_axes * 4] = {
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256,
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256,
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256,
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256
+};
+
+const short skin_macc_table[sh_css_num_macc_axes * 4] = {
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256,
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256,
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256,
+ 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256, 256, 0, 0, 256
+};
+
+struct sh_css_isp_cc_config default_cc_config = {
+ .fraction_bits = 8,
+ .matrix = {255, 29, 120, 0, -374, -342, 0, -672, 301},
+};
+
+struct hCss_isp_cc_config sepia_cc_config = {
+ .fraction_bits = 8,
+ .matrix = {255, 29, 120, 0, -374, -342, 0, -672, 301},
+};
+
+struct sh_css_isp_cc_config negative_cc_config = {
+ .fraction_bits = 8,
+ .matrix = {255, 29, 120, 0, -374, -342, 0, -672, 301},
+};
+
+struct sh_css_isp_cc_config mono_cc_config = {
+ .fraction_bits = 8,
+ .matrix = {255, 29, 120, 0, -374, -342, 0, -672, 301},
+};
+
+struct sh_css_isp_tnr_config default_tnr_config = {
+ .gain = 32768,
+ .threshold_y = 32,
+ .threshold_uv = 32,
+};
+
+struct sh_css_isp_ob_config default_ob_config = {
+ .mode = sh_css_isp_ob_mode_none,
+ .level_gr = 0,
+ .level_r = 0,
+ .level_b = 0,
+ .level_gb = 0,
+ .start_position = 0,
+ .end_position = 0
+};
+
+struct sh_css_isp_nr_config default_nr_config = {
+ .gain = 16384,
+ .direction = 1280,
+ .threshold_cb = 0,
+ .threshold_cr = 0
+};
+
+struct sh_css_isp_ee_config default_ee_config = {
+ .gain = 8192,
+ .threshold = 128,
+ .detail_gain = 2048
+};
+
+struct sh_css_isp_dp_config default_dp_config = {
+ .threshold = 8192,
+ .gain = 2048
+};
+
+#endif /* ISP_PARAM_H_ */
diff --git a/drivers/media/video/mfld_ci/mfldisp/include/mfldisp/mfldisp_internal.h b/drivers/media/video/mfld_ci/mfldisp/include/mfldisp/mfldisp_internal.h
new file mode 100644
index 0000000..cc389bf
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/include/mfldisp/mfldisp_internal.h
@@ -0,0 +1,134 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#ifndef MFLDISP_INTERNAL_H_
+#define MFLDISP_INTERNAL_H_
+
+#include <linux/kernel.h>
+
+#define LOG_LENGTH 100
+#define ISP_NAME "atomisp"
+#define mfld_isp_dbg(level, fmt, arg...) do {\
+ if (!(strcmp(level, KERN_INFO)) || \
+ !(strcmp(level, KERN_ERR))) {\
+ printk(level "%s: " fmt, "atomisp", ##arg); \
+ } \
+} while (0)
+
+extern void hrt_isp_css_mm_set_user_ptr(unsigned int userptr,
+ unsigned int num_pages);
+#ifdef USE_DYNAMIC_BIN
+#define HIVE_ADDR_sp_dma_proxy_run_entry 0x767
+#define HIVE_ADDR_sp_dma_proxy_init_entry 0xC42
+#define HIVE_ADDR_super_impose_offline_entry 0x543
+#define HIVE_ADDR_sp_gen_histogram_entry 0x420
+#define HIVE_ADDR_copy_frame_entry 0x2CD
+#define HIVE_ADDR_sp_bin_copy_entry 0x250
+#define HIVE_ADDR_sp_start_isp_entry 0x0
+
+#define _hrt_transfer_embedded_sp(code_func, data_func, bss_func, \
+ view_table_func, args...) \
+{\
+code_func(0x0, 0x0, 0x1E5F0, ## args);\
+data_func(scalar_processor_dmem, 0x4, 0x1E5F0, 0x2A1, ## args);\
+bss_func(scalar_processor_dmem, 0x2A8, 0x3860, ## args);\
+}
+
+
+extern char *_hrt_blob_sp;
+extern char *_hrt_blob_isp_bayer_ds_var;
+extern char *_hrt_blob_isp_copy_var;
+extern char *_hrt_blob_isp_primary_16mp;
+extern char *_hrt_blob_isp_primary_14mp;
+extern char *_hrt_blob_isp_primary_var;
+extern char *_hrt_blob_isp_primary_ds;
+extern char *_hrt_blob_isp_primary_small;
+extern char *_hrt_blob_isp_preview_var;
+extern char *_hrt_blob_isp_preview_ds;
+extern char *_hrt_blob_isp_video_online;
+extern char *_hrt_blob_isp_video_online_nodz;
+extern char *_hrt_blob_isp_video_online_ds;
+extern char *_hrt_blob_isp_video_offline;
+extern char *_hrt_blob_isp_xnr_var;
+extern char *_hrt_blob_isp_pregdc_var;
+extern char *_hrt_blob_isp_gdc_var;
+extern char *_hrt_blob_isp_postgdc_var;
+extern char *_hrt_blob_isp_vf_pp;
+
+extern unsigned int _hrt_text_size_of_sp;
+extern unsigned int _hrt_size_of_sp;
+
+extern unsigned int _hrt_text_size_of_isp_bayer_ds_var;
+extern unsigned int _hrt_size_of_isp_bayer_ds_var;
+
+extern unsigned int _hrt_text_size_of_isp_copy_var;
+extern unsigned int _hrt_size_of_isp_copy_var;
+
+extern unsigned int _hrt_text_size_of_isp_gdc_var;
+extern unsigned int _hrt_size_of_isp_gdc_var;
+
+extern unsigned int _hrt_text_size_of_isp_postgdc_var;
+extern unsigned int _hrt_size_of_isp_postgdc_var;
+
+extern unsigned int _hrt_text_size_of_isp_pregdc_var;
+extern unsigned int _hrt_size_of_isp_pregdc_var;
+
+extern unsigned int _hrt_text_size_of_isp_preview_ds;
+extern unsigned int _hrt_size_of_isp_preview_ds;
+
+extern unsigned int _hrt_text_size_of_isp_preview_var;
+extern unsigned int _hrt_size_of_isp_preview_var;
+
+extern unsigned int _hrt_text_size_of_isp_primary_14mp;
+extern unsigned int _hrt_size_of_isp_primary_14mp;
+
+extern unsigned int _hrt_text_size_of_isp_primary_16mp;
+extern unsigned int _hrt_size_of_isp_primary_16mp;
+
+extern unsigned int _hrt_text_size_of_isp_primary_ds;
+extern unsigned int _hrt_size_of_isp_primary_ds;
+
+extern unsigned int _hrt_text_size_of_isp_primary_small;
+extern unsigned int _hrt_size_of_isp_primary_small;
+
+extern unsigned int _hrt_text_size_of_isp_primary_var;
+extern unsigned int _hrt_size_of_isp_primary_var;
+
+extern unsigned int _hrt_text_size_of_isp_vf_pp;
+extern unsigned int _hrt_size_of_isp_vf_pp;
+
+extern unsigned int _hrt_text_size_of_isp_video_offline;
+extern unsigned int _hrt_size_of_isp_video_offline;
+
+extern unsigned int _hrt_text_size_of_isp_video_online_ds;
+extern unsigned int _hrt_size_of_isp_video_online_ds;
+
+extern unsigned int _hrt_text_size_of_isp_video_online_nodz;
+extern unsigned int _hrt_size_of_isp_video_online_nodz;
+
+extern unsigned int _hrt_text_size_of_isp_video_online;
+extern unsigned int _hrt_size_of_isp_video_online;
+
+extern unsigned int _hrt_text_size_of_isp_xnr_var;
+extern unsigned int _hrt_size_of_isp_xnr_var;
+#endif
+#endif /* MFLDISP_INTERNAL_H_ */
diff --git a/drivers/media/video/mfld_ci/mfldisp/include/mfldisp/mfldisp_sensor.h b/drivers/media/video/mfld_ci/mfldisp/include/mfldisp/mfldisp_sensor.h
new file mode 100644
index 0000000..f45782a
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/include/mfldisp/mfldisp_sensor.h
@@ -0,0 +1,67 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef _SensorParams_h_
+#define _SensorParams_h_
+
+#define MIPI_PORT_LANE_1 0
+#define MIPI_PORT_LANE_4 1
+
+
+#define BAYER_ORDER_GRBG 0
+#define BAYER_ORDER_RGGB 1
+#define BAYER_ORDER_BGGR 2
+#define BAYER_ORDER_GBRG 3
+
+#define INPUT_FORMAT_YUV420_8_LEGACY 0
+#define INPUT_FORMAT_YUV420_8 1
+#define INPUT_FORMAT_YUV420_10 2
+#define INPUT_FORMAT_YUV422_8 3
+#define INPUT_FORMAT_YUV422_10 4
+#define INPUT_FORMAT_RGB_444 5
+#define INPUT_FORMAT_RGB_555 6
+#define INPUT_FORMAT_RGB_565 7
+#define INPUT_FORMAT_RGB_666 8
+#define INPUT_FORMAT_RGB_888 9
+#define INPUT_FORMAT_RAW_6 10
+#define INPUT_FORMAT_RAW_7 11
+#define INPUT_FORMAT_RAW_8 12
+#define INPUT_FORMAT_RAW_10 13
+#define INPUT_FORMAT_RAW_12 14
+#define INPUT_FORMAT_RAW_14 15
+#define INPUT_FORMAT_RAW_16 16
+#define INPUT_FORMAT_BINARY_8 17
+
+struct mfld_ci_mipi_camera {
+ u32 port;
+ u32 num_of_lane;
+ u32 input_format;
+ u32 raw_bayer_order;
+ struct sh_css_shading_table*
+ (*get_shading_table)(unsigned int frame_width,
+ unsigned int frame_height,
+ unsigned int table_width,
+ unsigned int table_height);
+};
+
+#endif /* _SensorParams_h_ */
diff --git a/drivers/media/video/mfld_ci/mfldisp/include/mfldisp/mfldisp_v4l2.h b/drivers/media/video/mfld_ci/mfldisp/include/mfldisp/mfldisp_v4l2.h
new file mode 100644
index 0000000..00c4210
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/include/mfldisp/mfldisp_v4l2.h
@@ -0,0 +1,239 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef MFLDISP_V4L2_H_
+#define MFLDISP_V4L2_H_
+
+#define ATOMISP_MAJOR 0
+#define ATOMISP_MINOR 3
+#define ATOMISP_PATCHLEVEL 1
+
+#define DRIVER_VERSION_STR __stringify(ATOMISP_MAJOR) \
+ "." __stringify(ATOMISP_MINOR) "." __stringify(ATOMISP_PATCHLEVEL)
+#define DRIVER_VERSION KERNEL_VERSION(ATOMISP_MAJOR, \
+ ATOMISP_MINOR, ATOMISP_PATCHLEVEL)
+
+#define CI_MODE_PREVIEW 0x8000
+#define CI_MODE_VIDEO 0x4000
+#define CI_MODE_STILL_CAPTURE 0x2000
+#define CI_MODE_NONE 0x0000
+
+void *get_io_virt_addr(unsigned int address);
+
+#define MFLD_CI_I2C_BUS_1 4
+#define MFLD_CI_I2C_BUS_2 5
+
+#define CAMERA_SENSOR 0
+#define CAMERA_SENSOR_MOTOR 1
+#define XENON_FLASH 2
+#define LED_FLASH 3
+
+#define MFLD_WIDTH_RESTRICT 2
+#define MFLD_HEIGHT_RESTRICT 2
+
+/*#define MFLD_ISP_MAX_WIDTH 4608*/
+/*#define MFLD_ISP_MAX_HEIGHT 3450*/
+
+#define MFLD_ISP_MAX_WIDTH 1280
+#define MFLD_ISP_MAX_HEIGHT 720
+
+#include <linux/i2c.h>
+struct mfld_isp_subdev_info {
+ char *name;
+ u8 i2c_addr;
+ int i2c_id;
+};
+
+struct mfld_isp_subdev {
+ u32 subdev_type;
+ struct mfld_isp_subdev_info camera;
+ struct mfld_isp_subdev_info motor;
+ struct mfld_isp_subdev_info flash;
+};
+
+struct mfld_isp_3a_binary {
+ unsigned int mode;
+ int s3atbl_width;
+ int s3atbl_height;
+ int width;
+ int height;
+ int deci_factor;
+};
+
+#include "css/sh_css.h"
+
+struct mfld_isp_parm {
+ struct sh_css_grid_info info;
+ struct sh_css_isp_wb_config wb_config;
+ struct sh_css_isp_cc_config cc_config;
+ struct sh_css_isp_ob_config ob_config;
+ struct sh_css_isp_dp_config dp_config;
+ struct sh_css_isp_nr_config nr_config;
+ struct sh_css_isp_ee_config ee_config;
+ struct sh_css_isp_tnr_config tnr_config;
+};
+
+struct mfld_isp_dis_config {
+ int *w_sdis_vertproj_tbl;
+ int *w_sdis_horiproj_tbl;
+ short *sdis_vertcoef_tbl;
+ short *sdis_horicoef_tbl;
+ int dis_x;
+ int dis_y;
+};
+
+struct mfld_3a_stat {
+ void __user *w_3a_stat;
+};
+
+struct mfld_isp_gamma_tbl {
+ unsigned short gamma_table[1024];
+};
+
+/*Private IOCTLs for ISP */
+#define ATOMISP_IOC_G_XNR \
+ _IOR('v', BASE_VIDIOC_PRIVATE + 0, int)
+#define ATOMISP_IOC_S_XNR \
+ _IOW('v', BASE_VIDIOC_PRIVATE + 1, int)
+#define ATOMISP_IOC_G_BAYER_NR \
+ _IOR('v', BASE_VIDIOC_PRIVATE + 2, struct sh_css_isp_nr_config)
+#define ATOMISP_IOC_S_BAYER_NR \
+ _IOW('v', BASE_VIDIOC_PRIVATE + 3, struct sh_css_isp_nr_config)
+#define ATOMISP_IOC_G_TNR \
+ _IOR('v', BASE_VIDIOC_PRIVATE + 4, struct sh_css_isp_tnr_config)
+#define ATOMISP_IOC_S_TNR \
+ _IOW('v', BASE_VIDIOC_PRIVATE + 5, struct sh_css_isp_tnr_config)
+#define ATOMISP_IOC_G_HISTOGRAM \
+ _IOR('v', BASE_VIDIOC_PRIVATE + 6, struct sh_css_histogram)
+#define ATOMISP_IOC_S_HISTOGRAM \
+ _IOW('v', BASE_VIDIOC_PRIVATE + 7, struct sh_css_histogram)
+#define ATOMISP_IOC_G_BLACK_LEVEL_COMP \
+ _IOR('v', BASE_VIDIOC_PRIVATE + 8, struct sh_css_isp_ob_config)
+#define ATOMISP_IOC_S_BLACK_LEVEL_COMP \
+ _IOW('v', BASE_VIDIOC_PRIVATE + 9, struct sh_css_isp_ob_config)
+#define ATOMISP_IOC_G_YCC_NR \
+ _IOR('v', BASE_VIDIOC_PRIVATE + 10, struct sh_css_isp_nr_config)
+#define ATOMISP_IOC_S_YCC_NR \
+ _IOW('v', BASE_VIDIOC_PRIVATE + 11, struct sh_css_isp_nr_config)
+#define ATOMISP_IOC_G_EE \
+ _IOR('v', BASE_VIDIOC_PRIVATE + 12, struct sh_css_isp_ee_config)
+#define ATOMISP_IOC_S_EE \
+ _IOW('v', BASE_VIDIOC_PRIVATE + 13, struct sh_css_isp_ee_config)
+#define ATOMISP_IOC_G_DIS_STAT \
+ _IOW('v', BASE_VIDIOC_PRIVATE + 14, struct mfld_isp_dis_config)
+#define ATOMISP_IOC_S_DIS_STAT \
+ _IOW('v', BASE_VIDIOC_PRIVATE + 15, struct mfld_isp_dis_config)
+#define ATOMISP_IOC_G_3A_STAT \
+ _IOW('v', BASE_VIDIOC_PRIVATE + 16, struct mfld_3a_stat)
+#define ATOMISP_IOC_G_ISP_PARM \
+ _IOR('v', BASE_VIDIOC_PRIVATE + 17, struct mfld_isp_parm)
+#define ATOMISP_IOC_S_ISP_PARM \
+ _IOW('v', BASE_VIDIOC_PRIVATE + 18, struct mfld_isp_parm)
+#define ATOMISP_IOC_G_ISP_GAMMA \
+ _IOR('v', BASE_VIDIOC_PRIVATE + 19, struct mfld_isp_gamma_tbl)
+#define ATOMISP_IOC_S_ISP_GAMMA \
+ _IOW('v', BASE_VIDIOC_PRIVATE + 20, struct mfld_isp_gamma_tbl)
+
+/*Extended IDs for Camera Class*/
+#define V4L2_CID_CAMERA_LASTP1 \
+ (V4L2_CID_CAMERA_CLASS_BASE + 22)
+
+#define V4L2_CID_ISO_ABSOLUTE \
+ (V4L2_CID_CAMERA_LASTP1 + 0)
+#define V4L2_CID_APERTURE_ABSOLUTE \
+ (V4L2_CID_CAMERA_LASTP1 + 1)
+#define V4L2_CID_SS_EXPOSURE_ABSOLUTE \
+ (V4L2_CID_CAMERA_LASTP1 + 2)
+#define V4L2_CID_SS_ISO_ABSOLUTE \
+ (V4L2_CID_CAMERA_LASTP1 + 3)
+#define V4L2_CID_SS_APERTURE_ABSOLUTE \
+ (V4L2_CID_CAMERA_LASTP1 + 4)
+#define V4L2_CID_FLASH_DELAY \
+ (V4L2_CID_CAMERA_LASTP1 + 5)
+#define V4L2_CID_FLASH_DURATION \
+ (V4L2_CID_CAMERA_LASTP1 + 6)
+
+/* Flash and privacy (indicator) light controls */
+#define V4L2_CID_FLASH_STROBE (V4L2_CID_CAMERA_CLASS_BASE+17)
+#define V4L2_CID_FLASH_TIMEOUT (V4L2_CID_CAMERA_CLASS_BASE+18)
+#define V4L2_CID_FLASH_INTENSITY (V4L2_CID_CAMERA_CLASS_BASE+19)
+#define V4L2_CID_TORCH_INTENSITY (V4L2_CID_CAMERA_CLASS_BASE+20)
+#define V4L2_CID_INDICATOR_INTENSITY (V4L2_CID_CAMERA_CLASS_BASE+21)
+/*Private control IDs*/
+#define V4L2_CID_ATOMISP_BAD_PIXEL_DETECTION \
+ (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_ATOMISP_POSTPROCESS_GDC_CAC \
+ (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_ATOMISP_VIDEO_STABLIZATION \
+ (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_ATOMISP_FIXED_PATTERN_NR \
+ (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_ATOMISP_FALSE_COLOR_CORRECTION \
+ (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_ATOMISP_SHADING_CORRECTION \
+ (V4L2_CID_PRIVATE_BASE + 5)
+
+#ifdef USE_DYNAMIC_BIN
+/* This is for the firmware Loading from user space */
+struct bi_h {
+ int ID;
+ unsigned int offset;
+ unsigned int size;
+ unsigned int text_size;
+};
+
+struct bi_file_h {
+ int version;
+ int binary_nr;
+ unsigned int h_size;
+ unsigned int bi_offset;
+};
+
+enum isp_bin_binary_id {
+ isp_bin_sp,
+ isp_bin_copy_var,
+ isp_bin_bayer_ds_var,
+ isp_bin_vf_pp,
+ isp_bin_xnr_var,
+ isp_bin_pregdc_var,
+ isp_bin_gdc_var,
+ isp_bin_postgdc_var,
+ isp_bin_preview_var,
+ isp_bin_preview_ds,
+ isp_bin_primary_var,
+ isp_bin_primary_small,
+ isp_bin_primary_ds,
+ isp_bin_primary_14mp,
+ isp_bin_primary_16mp,
+ isp_bin_video_offline,
+ isp_bin_video_online,
+ isp_bin_video_online_nodz,
+ isp_bin_video_online_ds,
+ isp_binary_number,
+};
+
+#define FW_PATH "shisp.bin"
+#define SUPPORTED_BIN isp_binary_number
+#endif
+
+#endif /* MFLDISP_V4L2_H_ */
diff --git a/drivers/media/video/mfld_ci/mfldisp/mfldisp_v4l2.c b/drivers/media/video/mfld_ci/mfldisp/mfldisp_v4l2.c
new file mode 100644
index 0000000..477f309
--- /dev/null
+++ b/drivers/media/video/mfld_ci/mfldisp/mfldisp_v4l2.c
@@ -0,0 +1,4335 @@
+/*
+ * Support for Medifield PNW Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h> /* mfld_isp_dbg */
+#include <linux/version.h> /* mfld_isp_dbg */
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h> /* for kmalloc */
+#include <linux/mm.h> /* for GFP_ATOMIC */
+#include <linux/pci.h> /* for DMA */
+#include <linux/pm_runtime.h> /* for runtime pm */
+#include <linux/stringify.h>
+
+#include <linux/io.h> /* ioremap */
+#include <linux/uaccess.h> /* access_ok */
+#include <linux/param.h> /* access_ok */
+#include <asm/irq.h>
+#include <linux/poll.h>
+#include <linux/stddef.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/firmware.h>
+
+#include <asm/intel_scu_ipc.h>
+
+#include <hmm/hmm.h>
+
+/* SH header files */
+#include <css/sh_css.h>
+
+
+#include "mfldisp_v4l2.h"
+#include "mfldisp_internal.h"
+#include <mfldisp_sensor.h>
+#include "mfld_mem.h"
+#define CI_MAX_BUF_NUM 4
+#define video_num 4
+
+#define BITS_PER_PIXEL_RAW 16 /* raw type now */
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+
+/* TODO: translate css error into v4l2 error */
+#define return_on_css_error(stat) \
+ do { \
+ sh_css_err err = (stat); \
+ if (err != sh_css_success) { \
+ mfld_isp_dbg(KERN_ERR, "Error find in %s, %d\n", \
+ __func__, __LINE__); \
+ return -EINVAL; \
+ } \
+ } while (0)
+
+#define goto_on_css_error(stat, ret, err_label) \
+ do { \
+ ret = (stat); \
+ if (ret != sh_css_success) { \
+ mfld_isp_dbg(KERN_ERR, "Error find in %s, %d\n", \
+ __func__, __LINE__); \
+ goto err_label; \
+ } \
+ } while (0)
+
+/* for v4l2_capability */
+static const char *DRIVER = "atomisp"; /* max size 15 */
+static const char *CARD = "ATOM ISP MFLD"; /* max size 31 */
+static const char *BUS_INFO = "None"; /* max size 31 */
+static const __u32 VERSION = DRIVER_VERSION;
+static int nr = -1;
+static int isp_probe;
+
+struct ci_tvnorm {
+ char *name;
+ v4l2_std_id id;
+ u32 cxiformat;
+ u32 cxoformat;
+};
+
+struct ci_format {
+ __u32 pixelformat;
+ __u8 description[32]; /* the same as struct v4l2_fmtdesc */
+};
+
+struct ci_resolution {
+ __u32 width;
+ __u32 height;
+};
+
+struct ci_buffer {
+ struct sh_css_frame *handle;
+ __u32 size;
+ __u32 idx;
+ __u32 flags;
+
+ enum v4l2_memory buf_type;
+ /* for user ptr */
+ __u32 userptr;
+};
+
+struct ci_buffer_list {
+ struct list_head list;
+ struct ci_buffer *buf;
+};
+
+static struct ci_tvnorm tvnorms[] = {
+ {
+ .name = "CI Format",
+ .id = V4L2_STD_NTSC_M,
+ .cxiformat = 0,
+ .cxoformat = 0x181f0008,
+ },
+ {
+ .name = "CI Format NULL",
+ .id = V4L2_STD_NTSC_M_JP,
+ .cxiformat = 1,
+ .cxoformat = 0x181f0008,
+ }
+};
+
+/* subdev table */
+static struct mfld_isp_subdev mfld_isp_subdev_table[] = {
+ {
+ .subdev_type = CAMERA_SENSOR,
+ .camera = {
+ .name = "smiapp",
+ .i2c_addr = 0x10,
+ .i2c_id = MFLD_CI_I2C_BUS_1
+ }
+
+ },
+ {
+ .subdev_type = CAMERA_SENSOR,
+ .camera = {
+ .name = "dis71430m",
+ .i2c_addr = 0x69,
+ .i2c_id = MFLD_CI_I2C_BUS_1
+ }
+
+ },
+ {
+ .subdev_type = CAMERA_SENSOR,
+ .camera = {
+ .name = "ov2720",
+ .i2c_addr = 0x36,
+ .i2c_id = MFLD_CI_I2C_BUS_1,
+ }
+ },
+ {
+ .subdev_type = LED_FLASH,
+ .flash = {
+ .name = "mfld_ledflash",
+ .i2c_addr = 0x30,
+ .i2c_id = MFLD_CI_I2C_BUS_1,
+ }
+ },
+ {
+ .subdev_type = CAMERA_SENSOR_MOTOR,
+ .motor = {
+ .name = "ad58xx",
+ .i2c_addr = 0x0E,
+ .i2c_id = MFLD_CI_I2C_BUS_1,
+ }
+ },
+};
+
+#define N_SUBDEV \
+ (sizeof(mfld_isp_subdev_table)/sizeof(mfld_isp_subdev_table[0]))
+
+struct ci_camera_subdev {
+ u32 type;
+ struct v4l2_subdev *camera;
+ struct v4l2_subdev *motor;
+};
+
+enum frame_state {
+ S_UNUSED = 0, /* unused */
+ S_QUEUED, /* ready to capture */
+ S_GRABBING, /* in the process of being captured */
+ S_DONE, /* finished grabbing, but not been synced yet */
+ S_ERROR, /* something bad happened while capturing */
+};
+
+struct frame_info {
+ enum frame_state state;
+ u32 flags;
+};
+
+struct fifo {
+ int front;
+ int back;
+ int data[CI_MAX_BUF_NUM + 1];
+ struct frame_info info[CI_MAX_BUF_NUM + 1];
+};
+
+/*
+ * ci device struct
+ */
+struct ci_device {
+ struct v4l2_device v4l2_dev;
+ struct video_device *vdev;
+ int open;
+
+ __u32 width;
+ __u32 height;
+ __u32 pixelformat;
+ __u32 framesize;
+ __u32 pixeldepth;
+ __u32 bytesperline;
+ __u32 imagesize;
+
+ __u32 snr_width;
+ __u32 snr_height;
+ __u32 snr_max_width;
+ __u32 snr_max_height;
+ __u32 snr_pixelformat;
+
+ int buf_allocated;
+ __u32 bufnum;
+ struct ci_buffer **imagebuf; /* array of allocated buffers */
+ struct fifo buf_queue;
+ enum v4l2_memory buf_type;
+
+ struct ci_tvnorm *tvnorm;
+ int input;
+
+ struct sh_css_frame *vf_frame;
+ struct sh_css_frame *regular_output_frame;
+
+ enum sh_css_frame_format sh_pixelformat;
+
+ int camera_curr;
+ struct ci_camera_subdev cameras[N_SUBDEV];
+ struct v4l2_subdev *xenon_flash;
+ struct v4l2_subdev *led_flash;
+
+ int streaming;
+
+ int run_mode;
+ int online_process;
+ int bayer_downscaling;
+
+#ifdef MFLD_ASIC
+ void __iomem *base;
+#endif
+
+ /*OSPM related */
+ uint32_t apm_reg;
+ uint16_t apm_base;
+ uint32_t ospm_base;
+
+ struct sh_css_params *isp_params;
+
+ u32 color_effect;
+ u32 gdc_cac_en;
+ u32 bad_pixel_en;
+ u32 video_dis_en;
+ u32 sc_en;
+ u32 fpn_en;
+ u32 xnr_en;
+ int false_color;
+
+ struct sh_css_isp_ee_config *ee_config;
+ struct sh_css_isp_nr_config *nr_config;
+ struct sh_css_isp_tnr_config *tnr_config;
+ struct sh_css_isp_ob_config *ob_config;
+
+ int dis_x;
+ int dis_y;
+};
+
+#define _TO_CI_DEVICE(dev) container_of(dev, struct ci_device, vdev)
+
+/*
+ * input image data, and current frame resolution for test
+ */
+#define ISP_PARAM_MMAP_OFFSET 0xfffff000
+
+void __iomem *io_base;
+static struct ci_device *CI_DEV;
+struct video_device *VDEV;
+static const int vf_width = 640;
+static const int vf_height = 480;
+static const enum sh_css_frame_format vf_format = sh_css_frame_format_yuv420;
+
+struct v4l2_subdev *get_current_camera(struct ci_device *ci)
+{
+ if (ci->camera_curr < 0 || ci->camera_curr > 4)
+ return NULL;
+
+ return ci->cameras[ci->camera_curr].camera;
+}
+
+static struct mfld_ci_mipi_camera *to_sensor_mipi_info(struct v4l2_subdev *sd)
+{
+ return (struct mfld_ci_mipi_camera *)v4l2_get_subdevdata(sd);
+}
+/*
+ * supported V4L2 fmts and resolutions
+ */
+static const struct ci_format SUPPORTED_FMTS[] = {
+ {
+ .pixelformat = V4L2_PIX_FMT_YUV420,
+ .description = "YUV420, planner"},
+ {
+ .pixelformat = V4L2_PIX_FMT_YVU420,
+ .description = "YVU420, planner"},
+ {
+ .pixelformat = V4L2_PIX_FMT_YUV422P,
+ .description = "YUV422, planner"},
+ {
+ .pixelformat = V4L2_PIX_FMT_YUV444,
+ .description = "YUV444"},
+ {
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ .description = "NV12, interleaved"},
+ {
+ .pixelformat = V4L2_PIX_FMT_NV21,
+ .description = "NV21, interleaved"},
+ {
+ .pixelformat = V4L2_PIX_FMT_NV16,
+ .description = "NV16, interleaved"},
+ {
+ .pixelformat = V4L2_PIX_FMT_NV61,
+ .description = "NV61, interleaved"},
+ {
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .description = "YUYV, interleaved"},
+ {
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .description = "UYVY, interleaved"},
+ {
+ .pixelformat = V4L2_PIX_FMT_SBGGR16,
+ .description = "Bayer 16"},
+ {
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ .description = "Bayer 8"},
+ {
+ .pixelformat = V4L2_PIX_FMT_SGBRG8,
+ .description = "Bayer 8"},
+ {
+ .pixelformat = V4L2_PIX_FMT_SGRBG8,
+ .description = "Bayer 8"},
+ {
+ .pixelformat = V4L2_PIX_FMT_SRGGB8,
+ .description = "Bayer 8"},
+ {
+ .pixelformat = V4L2_PIX_FMT_SBGGR10,
+ .description = "Bayer 10"},
+ {
+ .pixelformat = V4L2_PIX_FMT_SGBRG10,
+ .description = "Bayer 10"},
+ {
+ .pixelformat = V4L2_PIX_FMT_SGRBG10,
+ .description = "Bayer 10"},
+ {
+ .pixelformat = V4L2_PIX_FMT_SRGGB10,
+ .description = "Bayer 10"},
+ {
+ .pixelformat = V4L2_PIX_FMT_RGB24,
+ .description = "24 RGB 8-8-8"},
+ {
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ .description = "32 RGB 8-8-8-8"},
+ {
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .description = "16 RGB 5-6-5"}
+};
+
+static const __u32 SUPPORTED_FMT_NUM =
+ sizeof(SUPPORTED_FMTS) / sizeof(SUPPORTED_FMTS[0]);
+
+static struct ci_resolution SUPPORTED_RESOLUTIONS[] = {
+ {.width = 4352, .height = 3264},
+ /*{.width = 2560, .height = 1920}, */
+ {.width = 1920, .height = 1080},
+ {.width = 1280, .height = 720},
+ {.width = 640, .height = 480}
+};
+
+static const __u32 SUPPORTED_RESOLUTION_NUM =
+ sizeof(SUPPORTED_RESOLUTIONS) / sizeof(SUPPORTED_RESOLUTIONS[0]);
+
+struct v4l2_queryctrl ci_v4l2_controls[] = {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic Gain Control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x00,
+ },
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x00,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Shutter Control",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x00,
+ },
+ {
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x00,
+ },
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Image h-flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Image v-flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_COLORFX,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Image Color Effect",
+ .minimum = 0,
+ .maximum = 9,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_ATOMISP_BAD_PIXEL_DETECTION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Bad Pixel Correction",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_ATOMISP_POSTPROCESS_GDC_CAC,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "GDC/CAC",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_ATOMISP_VIDEO_STABLIZATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Video Stablization",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_ATOMISP_FIXED_PATTERN_NR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Fixed Pattern Noise Reduction",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_ATOMISP_FALSE_COLOR_CORRECTION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "False Color Correction",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_ATOMISP_SHADING_CORRECTION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Lens Shading Correction",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ }
+};
+
+static const __u32 SUPPORTED_CTRL_NUM =
+ sizeof(ci_v4l2_controls) / sizeof(ci_v4l2_controls[0]);
+
+static inline void MSG_WRITE32(uint port, uint offset, u32 value);
+static inline u32 MSG_READ32(uint port, uint offset);
+
+void *get_io_virt_addr(unsigned int address)
+{
+ unsigned int ret = 0;
+
+ ret = (unsigned int)io_base + (address & 0x003FFFFF);
+
+ return (void *)ret;
+}
+
+/*
+ * utils for buffer allocation/free
+ */
+static inline unsigned long kvirt_to_pa(void *virt)
+{
+ __u32 kva;
+
+ kva = (unsigned long)page_address(vmalloc_to_page(virt));
+ kva |= ((__u32) virt) & (PAGE_SIZE - 1); /* restore the offset */
+ return __pa(kva);
+}
+
+#define __bytes_to_pgnr_ceil(bytes) \
+ (((bytes) + ((1<<PAGE_SHIFT) - 1)) >> PAGE_SHIFT)
+
+int get_frame_pgnr(const struct sh_css_frame *frame, __u32 * p_pgnr)
+{
+ if (!frame) {
+ mfld_isp_dbg(KERN_ERR, "NULL frame pointer.\n");
+ return -EINVAL;
+ }
+
+ (*p_pgnr) = __bytes_to_pgnr_ceil(frame->data_bytes);
+ return 0;
+}
+
+#define alloc_buffer(handle) __alloc_buffer(handle, 0)
+
+static struct ci_buffer *__alloc_buffer(struct sh_css_frame *handle,
+ __u32 flags)
+{
+ __u32 pgnr;
+ struct ci_buffer *buffer;
+
+ mfld_isp_dbg(KERN_DEBUG, "__alloc_isp_buffer\n");
+
+ if (!handle) {
+ mfld_isp_dbg(KERN_ERR, "NULL ISP buffer pointer!\n");
+ return NULL;
+ }
+
+ buffer = kmalloc(sizeof(struct ci_buffer), GFP_KERNEL);
+ if (buffer == NULL) {
+ mfld_isp_dbg(KERN_ERR, "out of memory\n");
+ return NULL;
+ }
+ memset(buffer, 0, sizeof(struct ci_buffer));
+
+ buffer->handle = handle;
+ buffer->flags = flags;
+
+ get_frame_pgnr(handle, &pgnr);
+ buffer->size = (pgnr << PAGE_SHIFT);
+
+ buffer->buf_type = V4L2_MEMORY_MMAP;
+
+ mfld_isp_dbg(KERN_DEBUG, "alloc_buffer: %u pages, %u bytes.\n",
+ pgnr, buffer->size);
+
+ return buffer;
+}
+
+#define alloc_user_buffer(handle, userptr, pgnr, index) \
+ __alloc_user_buffer(handle, 0, userptr, pgnr, index)
+
+static struct ci_buffer *__alloc_user_buffer(struct sh_css_frame *handle,
+ __u32 flags, __u32 userptr,
+ __u32 pgnr, __u32 index)
+{
+ __u32 __pgnr;
+ struct ci_buffer *buffer;
+
+ mfld_isp_dbg(KERN_DEBUG, "__alloc_isp_buffer\n");
+
+ if (!handle) {
+ mfld_isp_dbg(KERN_ERR, "NULL ISP buffer pointer!\n");
+ return NULL;
+ }
+
+ buffer = kmalloc(sizeof(struct ci_buffer), GFP_KERNEL);
+ if (buffer == NULL) {
+ mfld_isp_dbg(KERN_ERR, "out of memory\n");
+ return NULL;
+ }
+ memset(buffer, 0, sizeof(struct ci_buffer));
+
+ buffer->handle = handle;
+ buffer->flags = flags;
+
+ get_frame_pgnr(handle, &__pgnr);
+
+ if (__pgnr != pgnr)
+ mfld_isp_dbg(KERN_ERR, "user memory size is not the same"
+ " as expected...\n");
+
+ buffer->size = (__pgnr << PAGE_SHIFT);
+
+ mfld_isp_dbg(KERN_DEBUG, "alloc_buffer: %u pages, %u bytes.\n",
+ __pgnr, buffer->size);
+
+ buffer->userptr = userptr;
+
+ buffer->buf_type = V4L2_MEMORY_USERPTR;
+ buffer->idx = index;
+
+ return buffer;
+}
+
+static void free_buffer(struct ci_buffer *buf)
+{
+ kfree(buf);
+}
+
+/*
+ * get SH fmt according to V4L2 fmt
+ */
+static enum sh_css_frame_format v4l2_fmt_to_sh_fmt(__u32 fmt)
+{
+ switch (fmt) {
+ case V4L2_PIX_FMT_YUV420:
+ return sh_css_frame_format_yuv420;
+ case V4L2_PIX_FMT_YVU420:
+ return sh_css_frame_format_yv12;
+ case V4L2_PIX_FMT_YUV422P:
+ return sh_css_frame_format_yuv422;
+ case V4L2_PIX_FMT_YUV444:
+ return sh_css_frame_format_yuv444;
+ case V4L2_PIX_FMT_NV12:
+ return sh_css_frame_format_nv12;
+ case V4L2_PIX_FMT_NV21:
+ return sh_css_frame_format_nv21;
+ case V4L2_PIX_FMT_NV16:
+ return sh_css_frame_format_nv16;
+ case V4L2_PIX_FMT_NV61:
+ return sh_css_frame_format_nv61;
+ case V4L2_PIX_FMT_UYVY:
+ return sh_css_frame_format_uyvy;
+ case V4L2_PIX_FMT_YUYV:
+ return sh_css_frame_format_yuyv;
+ case V4L2_PIX_FMT_RGB24:
+ return sh_css_frame_format_planar_rgb888;
+ case V4L2_PIX_FMT_RGB32:
+ return sh_css_frame_format_rgba888;
+ case V4L2_PIX_FMT_RGB565:
+ return sh_css_frame_format_rgb565;
+ case V4L2_PIX_FMT_SBGGR16:
+ return sh_css_frame_format_vraw16;
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ return sh_css_frame_format_raw16;
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ return sh_css_frame_format_raw8;
+ default:
+ return -1;
+ }
+}
+
+static struct ci_format *get_ci_format(__u32 pixelformat)
+{
+ __u32 i;
+ for (i = 0; i < SUPPORTED_FMT_NUM; i++) {
+ if (SUPPORTED_FMTS[i].pixelformat == pixelformat)
+ return (struct ci_format *)(&(SUPPORTED_FMTS[i]));
+ }
+ return NULL;
+}
+
+static __u32 get_pixel_depth(__u32 pixelformat)
+{
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_YVU420:
+ return 12;
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_SBGGR16:
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ return 16;
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_YUV444:
+ return 24;
+ case V4L2_PIX_FMT_RGB32:
+ return 32;
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ return 8;
+ default:
+ return 8 * 2; /* raw type now */
+ }
+}
+
+static int is_pixelformat_supported(__u32 pixelformat)
+{
+ int i;
+
+ for (i = 0; i < SUPPORTED_FMT_NUM; i++) {
+ mfld_isp_dbg(KERN_WARNING,
+ "pixel try %x, %x\n", pixelformat,
+ SUPPORTED_FMTS[i].pixelformat);
+ if (pixelformat == SUPPORTED_FMTS[i].pixelformat)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int is_resolution_supported(__u32 width, __u32 height)
+{
+ int i;
+
+ mfld_isp_dbg(KERN_DEBUG,
+ "SUPPORTED_RESOLUTION_NUM: %d\n",
+ SUPPORTED_RESOLUTION_NUM);
+ for (i = 0; i < SUPPORTED_RESOLUTION_NUM; i++) {
+ if (width == SUPPORTED_RESOLUTIONS[i].width &&
+ height == SUPPORTED_RESOLUTIONS[i].height)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* MFLD ISP feature control */
+static int mfld_isp_gdc_cac(struct ci_device *ci, int flag, __s32 * value);
+static int mfld_isp_xnr(struct ci_device *ci, int flag, int *arg)
+{
+ int xnr_enable = (*arg == 0) ? 0 : 1;
+ int gdc_enable = 1;
+
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (flag == 0) {
+ *arg = ci->xnr_en;
+ return 0;
+ }
+
+ if (ci->run_mode == CI_MODE_STILL_CAPTURE) {
+ if (!ci->gdc_cac_en && xnr_enable == 1)
+ mfld_isp_gdc_cac(ci, 1, &gdc_enable);
+ sh_css_capture_enable_xnr(xnr_enable);
+ }
+ return 0;
+}
+
+static int mfld_isp_bayer_nr(struct ci_device *ci, int flag,
+ struct sh_css_isp_nr_config *arg)
+{
+ const struct sh_css_isp_ee_config **default_ee_config = NULL;
+
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (arg == NULL)
+ return -EINVAL;
+
+ /* Get nr config from current setup */
+ if (flag == 0) {
+ memcpy(arg, ci->nr_config, sizeof(struct sh_css_isp_nr_config));
+ return 0;
+ }
+
+ /* Set nr config to isp parameters */
+ sh_css_params_get_default_ee_config(default_ee_config);
+ sh_css_params_configure_nree(ci->isp_params, arg, *default_ee_config);
+ memcpy(ci->nr_config, arg, sizeof(struct sh_css_isp_nr_config));
+
+ return 0;
+}
+
+static int mfld_isp_tnr(struct ci_device *ci, int flag,
+ struct sh_css_isp_tnr_config *arg)
+{
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (arg == NULL)
+ return -EINVAL;
+
+ /* Get tnr config from current setup */
+ if (flag == 0) {
+ memcpy(arg, ci->tnr_config,
+ sizeof(struct sh_css_isp_tnr_config));
+ return 0;
+ }
+
+ if (arg->threshold_y == 0 && arg->threshold_uv == 0)
+
+ /* Set tnr config to isp parameters */
+ sh_css_params_configure_tnr(ci->isp_params, arg);
+ memcpy(ci->tnr_config, arg, sizeof(struct sh_css_isp_tnr_config));
+
+ return 0;
+}
+
+static int mfld_isp_histogram(struct ci_device *ci, int flag, void *arg)
+{
+ return 0;
+}
+
+static int mfld_isp_black_level(struct ci_device *ci, int flag,
+ struct sh_css_isp_ob_config *arg)
+{
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (arg == NULL)
+ return -EINVAL;
+
+ /* Get ob config from current setup */
+ if (flag == 0) {
+ memcpy(arg, ci->ob_config, sizeof(struct sh_css_isp_ob_config));
+ return 0;
+ }
+
+ /* Set ob config to isp parameters */
+ sh_css_params_configure_ob(ci->isp_params, arg);
+ memcpy(ci->ob_config, arg, sizeof(struct sh_css_isp_ob_config));
+
+ return 0;
+}
+
+static int mfld_isp_ycc_nr(struct ci_device *ci, int flag,
+ struct sh_css_isp_nr_config *arg)
+{
+ const struct sh_css_isp_ee_config **default_ee_config = NULL;
+
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (arg == NULL)
+ return -EINVAL;
+
+ /* Get nr config from current setup */
+ if (flag == 0) {
+ memcpy(arg, ci->nr_config, sizeof(struct sh_css_isp_nr_config));
+ return 0;
+ }
+
+ /* Set nr config to isp parameters */
+ sh_css_params_get_default_ee_config(default_ee_config);
+ sh_css_params_configure_nree(ci->isp_params, arg, *default_ee_config);
+ memcpy(ci->nr_config, arg, sizeof(struct sh_css_isp_nr_config));
+
+ return 0;
+}
+
+static int mfld_isp_ee(struct ci_device *ci, int flag,
+ struct sh_css_isp_ee_config *arg)
+{
+ const struct sh_css_isp_nr_config **default_nr_config = NULL;
+
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (arg == NULL)
+ return -EINVAL;
+
+ /* Get ee config from current setup */
+ if (flag == 0) {
+ memcpy(arg, ci->ee_config, sizeof(struct sh_css_isp_ee_config));
+ return 0;
+ }
+
+ /* Set ee config to isp parameters */
+ sh_css_params_get_default_nr_config(default_nr_config);
+ sh_css_params_configure_nree(ci->isp_params, *default_nr_config, arg);
+ memcpy(ci->ee_config, arg, sizeof(struct sh_css_isp_ee_config));
+ return 0;
+}
+
+static int mfld_isp_set_gamma(struct ci_device *ci, int flag,
+ struct mfld_isp_gamma_tbl *arg)
+{
+ sh_css_params_set_gamma_table(ci->isp_params, arg->gamma_table);
+ return 0;
+}
+
+static int mfld_isp_get_gamma(struct ci_device *ci, int flag,
+ struct mfld_isp_gamma_tbl *arg)
+{
+ sh_css_params_get_gamma_table(ci->isp_params, arg->gamma_table);
+ return 0;
+}
+
+static int mfld_isp_dis_stat(struct ci_device *ci, int flag,
+ struct mfld_isp_dis_config *arg)
+{
+ int width_size, height_size;
+ int error;
+ int *w_sdis_hori_proj = NULL, *w_sdis_vert_proj = NULL;
+ short *sdis_hori_coef = NULL, *sdis_vert_coef = NULL;
+ struct sh_css_grid_info info;
+
+ switch (ci->run_mode) {
+ case CI_MODE_PREVIEW:
+ sh_css_preview_get_grid_info(&info);
+ break;
+ case CI_MODE_VIDEO:
+ sh_css_video_get_grid_info(&info);
+ break;
+ default:
+ sh_css_capture_get_grid_info(&info);
+ break;
+ }
+
+ if (flag == 0) {
+ if (arg->w_sdis_vertproj_tbl == NULL ||
+ arg->w_sdis_horiproj_tbl == NULL)
+ return -EINVAL;
+
+ width_size = sh_css_num_dis_coef_types * info.width_dis
+ * sizeof(int);
+ height_size = sh_css_num_dis_coef_types * info.height_dis
+ * sizeof(int);
+ w_sdis_hori_proj = kmalloc(height_size, GFP_KERNEL);
+ if (w_sdis_hori_proj == NULL) {
+ mfld_isp_dbg(KERN_ERR, "Failed to request memory\n");
+ return -ENOMEM;
+ }
+ w_sdis_vert_proj = kmalloc(width_size, GFP_KERNEL);
+ if (w_sdis_vert_proj == NULL) {
+ mfld_isp_dbg(KERN_ERR, "Failed to request memory\n");
+ kfree(w_sdis_hori_proj);
+ return -ENOMEM;
+ }
+
+ sh_css_params_dis_get_projections(w_sdis_hori_proj,
+ w_sdis_vert_proj);
+
+ error = copy_to_user(arg->w_sdis_vertproj_tbl,
+ w_sdis_vert_proj,
+ sh_css_num_dis_coef_types * info.width_dis
+ * sizeof(int));
+
+ error = copy_to_user(arg->w_sdis_horiproj_tbl,
+ w_sdis_hori_proj,
+ sh_css_num_dis_coef_types * info.height_dis
+ * sizeof(int));
+
+ arg->dis_x = ci->dis_x;
+ arg->dis_y = ci->dis_y;
+
+ kfree(w_sdis_hori_proj);
+ kfree(w_sdis_vert_proj);
+ } else {
+ if (arg->sdis_vertcoef_tbl == NULL ||
+ arg->sdis_horicoef_tbl == NULL)
+ return -EINVAL;
+
+ width_size = sizeof(short) *sh_css_num_dis_coef_types *
+ info.dis_vertcoef_num;
+ height_size = sizeof(short) *sh_css_num_dis_coef_types *
+ info.dis_horicoef_num;
+ sh_css_params_dis_get_coefficients(&sdis_hori_coef,
+ &sdis_vert_coef);
+ error = copy_from_user(sdis_hori_coef,
+ (void __user *)arg->sdis_horicoef_tbl,
+ height_size);
+ error = copy_from_user(sdis_vert_coef,
+ (void __user *)arg->sdis_vertcoef_tbl,
+ width_size);
+
+ ci->dis_x = arg->dis_x;
+ ci->dis_y = arg->dis_y;
+ }
+ return 0;
+}
+
+static int mfld_isp_3a_stat(struct ci_device *ci, int flag,
+ struct mfld_3a_stat *arg)
+{
+ struct sh_css_grid_info info;
+ struct sh_css_isp_3a_output *output;
+ unsigned int bytes;
+ unsigned long ret;
+
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (flag != 0)
+ return -EINVAL;
+
+ if (arg == NULL)
+ return -EINVAL;
+
+ switch (ci->run_mode) {
+ case CI_MODE_STILL_CAPTURE:
+ sh_css_capture_get_grid_info(&info);
+ break;
+ case CI_MODE_PREVIEW:
+ sh_css_preview_get_grid_info(&info);
+ break;
+ case CI_MODE_VIDEO:
+ sh_css_video_get_grid_info(&info);
+ break;
+ }
+
+ bytes =
+ info.width_3a * info.height_3a * sizeof(struct
+ sh_css_isp_3a_output);
+ output = kmalloc(bytes, GFP_KERNEL);
+
+ sh_css_params_3a_get_statistics(output);
+ ret = copy_to_user(arg->w_3a_stat, output, bytes);
+ if (ret)
+ mfld_isp_dbg(KERN_DEBUG,
+ "copy to user failed copied %lu bytes\n", ret);
+
+#ifdef CI_ISP_DEBUG
+ int i;
+ /*for (i = 0; i < info.width_3a * info.height_3a; i++) { */
+ for (i = 0; i < 10; i++) {
+ struct sh_css_isp_3a_output *pt;
+ pt = output + i * sizeof(struct sh_css_isp_3a_output);
+ mfld_isp_dbg(KERN_DEBUG, "Get 3A stat from kernel %d\n", i);
+ mfld_isp_dbg(KERN_DEBUG, "ae_y = %d\n", pt->ae_Y);
+ mfld_isp_dbg(KERN_DEBUG, "awb_cnt = %d\n", pt->awb_cnt);
+ mfld_isp_dbg(KERN_DEBUG, "awb_GR = %d\n", pt->awb_GR);
+ mfld_isp_dbg(KERN_DEBUG, "awb_R = %d\n", pt->awb_R);
+ mfld_isp_dbg(KERN_DEBUG, "awb_B = %d\n", pt->awb_B);
+ mfld_isp_dbg(KERN_DEBUG, "awb_GB = %d\n", pt->awb_GB);
+ mfld_isp_dbg(KERN_DEBUG, "af_hpf1 = %d\n", pt->af_hpf1);
+ mfld_isp_dbg(KERN_DEBUG, "af_hpf2 = %d\n", pt->af_hpf2);
+ }
+#endif
+ kfree(output);
+ return 0;
+}
+
+static int mfld_isp_param(struct ci_device *ci, int flag,
+ struct mfld_isp_parm *arg)
+{
+ struct sh_css_grid_info *info;
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+
+ /* Read parameter for 3A bianry info */
+ if (flag == 0) {
+ if (&arg->info == NULL) {
+ mfld_isp_dbg(KERN_ERR, "NULL pointer in grid_info\n");
+ return -EINVAL;
+ }
+
+ info = &arg->info;
+ switch (ci->run_mode) {
+ case CI_MODE_STILL_CAPTURE:
+ sh_css_capture_get_grid_info(info);
+ break;
+ case CI_MODE_PREVIEW:
+ sh_css_preview_get_grid_info(info);
+ break;
+ case CI_MODE_VIDEO:
+ sh_css_video_get_grid_info(info);
+ break;
+ }
+ return 0;
+ }
+
+ sh_css_params_configure_wb(ci->isp_params, &arg->wb_config);
+ sh_css_params_configure_cc(ci->isp_params, &arg->cc_config);
+ sh_css_params_configure_ob(ci->isp_params, &arg->ob_config);
+ sh_css_params_configure_dp(ci->isp_params, &arg->dp_config);
+ sh_css_params_configure_nree(ci->isp_params, &arg->nr_config,
+ &arg->ee_config);
+ sh_css_params_configure_tnr(ci->isp_params, &arg->tnr_config);
+#ifdef CI_ISP_DEBUG
+ struct sh_css_isp_wb_config *wb_config = &arg->wb_config;
+ struct sh_css_isp_cc_config *cc_config = &arg->cc_config;
+ struct sh_css_isp_ob_config *ob_config = &arg->ob_config;
+ mfld_isp_dbg(KERN_DEBUG, "wb: gr = %x, r = %x, b = %x, gb = %x\n",
+ wb_config->gr, wb_config->r,
+ wb_config->b, wb_config->gb);
+ mfld_isp_dbg(KERN_DEBUG, "CC matrix, %d, %d, %d, %d, %d, %d\n",
+ cc_config->matrix[0], cc_config->matrix[1],
+ cc_config->matrix[2], cc_config->matrix[3],
+ cc_config->matrix[4], cc_config->matrix[5]);
+ mfld_isp_dbg(KERN_DEBUG, "OB: gr %x, r %x, b %x, gb %x\n",
+ ob_config->level_gr, ob_config->level_r,
+ ob_config->level_b, ob_config->level_gb);
+#endif
+ return 0;
+}
+
+static const struct sh_css_isp_cc_config sepia_cc_config = {
+ .fraction_bits = 8,
+ .matrix = {141, 18, 68, -40, -5, -19, 35, 4, 16},
+};
+
+static const struct sh_css_isp_cc_config nega_cc_config = {
+ .fraction_bits = 8,
+ .matrix = {255, 29, 120, 0, 374, 342, 0, 672, -301},
+};
+
+static const struct sh_css_isp_cc_config mono_cc_config = {
+ .fraction_bits = 8,
+ .matrix = {255, 29, 120, 0, 0, 0, 0, 0, 0},
+};
+
+static const short skin_macc_table[] = {
+ 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192,
+ 8192, 4096, 0, 6144, 7168, 2048, -1024, 4096, 6144, 0, 4096, 8192, 4096,
+ -1024, 2048, 7168,
+ 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192,
+ 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192
+};
+
+static const short blue_macc_table[] = {
+ 24576, -16384, 0, 16384, 24576, -16384, 8192, 0, 8192, 0, 0, 8192, 8192,
+ 0, 0, 8192,
+ 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192,
+ 24576, 0, 0, 24576, 32767, 16384, -8192, 8192, 8192, 0, 0, 8192, 24576,
+ 8192, -16384, 0,
+ 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192
+};
+
+static const short green_macc_table[] = {
+ 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192,
+ 16384, 16384, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 0,
+ 8192,
+ 8192, 0, 0, 8192, 8192, 0, 0, 8192, 8192, 0, 16384, 16384, 8192, 0, 0,
+ 8192,
+ 16384, 16384, 0, 24576, 20480, 8192, -4096, 32767, 24576, 0, 16384,
+ 16384, 32767, -4096, 8192, 20480
+};
+
+static unsigned short vivid_ctc_table[] = {
+ 0, 0, 0
+};
+
+static int mfld_isp_color_effect(struct ci_device *ci, int flag, __s32 *effect)
+{
+ const struct sh_css_isp_cc_config *cc_config = NULL;
+ const short *macc_table = NULL;
+ const unsigned short *ctc_table = NULL;
+ const short *default_macc_table[1];
+ const struct sh_css_isp_cc_config *default_cc_config[1];
+ const unsigned short *default_ctc_table[1];
+
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (flag == 0) {
+ *effect = ci->color_effect;
+ return 0;
+ }
+
+ if (*effect == ci->color_effect)
+ return 0;
+
+ switch (*effect) {
+ case V4L2_COLORFX_NONE:
+ sh_css_params_get_default_macc_table(default_macc_table);
+ sh_css_params_get_default_cc_config(default_cc_config);
+ sh_css_params_get_default_ctc_table(default_ctc_table);
+ cc_config = *default_cc_config;
+ macc_table = *default_macc_table;
+ ctc_table = *default_ctc_table;
+ break;
+ case V4L2_COLORFX_SEPIA:
+ cc_config = (const struct sh_css_isp_cc_config *)
+ &sepia_cc_config;
+ break;
+ case V4L2_COLORFX_NEGATIVE:
+ cc_config = &nega_cc_config;
+ break;
+ case V4L2_COLORFX_BW:
+ cc_config = &mono_cc_config;
+ break;
+ case V4L2_COLORFX_SKY_BLUE:
+ macc_table = blue_macc_table;
+ break;
+ case V4L2_COLORFX_GRASS_GREEN:
+ macc_table = green_macc_table;
+ break;
+ case V4L2_COLORFX_SKIN_WHITEN:
+ macc_table = skin_macc_table;
+ break;
+ case V4L2_COLORFX_VIVID:
+ ctc_table = vivid_ctc_table;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (cc_config)
+ sh_css_params_configure_cc(ci->isp_params, cc_config);
+ if (macc_table)
+ sh_css_params_set_macc_table(ci->isp_params, macc_table);
+ if (ctc_table)
+ sh_css_params_set_ctc_table(ci->isp_params,
+ (unsigned short *)ctc_table);
+ ci->color_effect = (u32)*effect;
+ return 0;
+}
+
+static int mfld_isp_bad_pixel(struct ci_device *ci, int flag, __s32 *value)
+{
+ struct sh_css_isp_dp_config dp_config;
+ const struct sh_css_isp_dp_config **default_dp_config = NULL;
+
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (flag == 0) {
+ *value = ci->bad_pixel_en;
+ return 0;
+ }
+
+ if (*value == ci->bad_pixel_en)
+ return 0;
+
+ if (*value) {
+ sh_css_params_get_default_dp_config(default_dp_config);
+ memcpy(&dp_config, *default_dp_config,
+ (sizeof(default_dp_config)));
+ } else {
+ dp_config.threshold = 0xFFFF;
+ dp_config.gain = 0xFFFF;
+ }
+
+ sh_css_params_configure_dp(ci->isp_params, &dp_config);
+ ci->bad_pixel_en = (*value == 0) ? 0 : 1;
+
+ return 0;
+}
+
+static int mfld_isp_gdc_cac(struct ci_device *ci, int flag, __s32 * value)
+{
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (flag == 0) {
+ *value = ci->gdc_cac_en;
+ return 0;
+ }
+
+ if (ci->run_mode == CI_MODE_STILL_CAPTURE) {
+ sh_css_capture_set_mode(sh_css_capture_mode_advanced);
+ ci->gdc_cac_en = (*value == 0) ? 0 : 1;
+ }
+
+ return 0;
+}
+
+static int mfld_isp_video_stable(struct ci_device *ci, int flag, __s32 * value)
+{
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (flag == 0) {
+ *value = ci->video_dis_en;
+ return 0;
+ }
+
+ if (ci->run_mode == CI_MODE_VIDEO)
+ ci->video_dis_en = (*value == 0) ? 0 : 1;
+
+ return 0;
+}
+
+static int mfld_isp_fixed_pattern(struct ci_device *ci, int flag, __s32 * value)
+{
+ struct sh_css_frame *raw_black_frame = NULL;
+
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (flag == 0) {
+ *value = ci->fpn_en;
+ return 0;
+ }
+
+ if (*value == 0) {
+ /*ci->isp_params->isp_parameters.fpn_enabled = 0;*/
+ ci->fpn_en = 0;
+ return 0;
+ }
+
+ /* Add function to get black from from sensor with shutter off */
+ sh_css_params_set_black_frame(ci->isp_params, raw_black_frame);
+ ci->fpn_en = 1;
+ return 0;
+}
+
+static int mfld_isp_false_color(struct ci_device *ci, int flag, __s32 * value)
+{
+ const struct sh_css_isp_de_config *default_de_config[1];
+ struct sh_css_isp_de_config de_config;
+ /* Get nr config from current setup */
+ if (flag == 0) {
+ *value = ci->false_color;
+ return 0;
+ }
+
+ /* Set nr config to isp parameters */
+ sh_css_params_get_default_de_config(default_de_config);
+ memcpy(&de_config, *default_de_config,
+ sizeof(struct sh_css_isp_de_config));
+ de_config.pixelnoise = *value;
+ sh_css_params_configure_de(ci->isp_params, &de_config);
+ ci->false_color = *value;
+ return 0;
+}
+
+static int mfld_isp_shading_correction(struct ci_device *ci, int flag,
+ __s32 *value)
+{
+ struct mfld_ci_mipi_camera *mipi_info;
+ struct sh_css_shading_table* (*shading_table_func)
+ (unsigned int frame_width,
+ unsigned int frame_height,
+ unsigned int table_width,
+ unsigned int table_height) = NULL;
+
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (flag == 0) {
+ *value = ci->sc_en;
+ return 0;
+ }
+
+ if (*value == 0) {
+ sh_css_set_get_shading_table(NULL);
+ ci->sc_en = 0;
+ return 0;
+ }
+
+ /* set the shading table function */
+ mipi_info = to_sensor_mipi_info(ci->cameras[ci->camera_curr].camera);
+ shading_table_func = mipi_info->get_shading_table;
+ sh_css_set_get_shading_table(shading_table_func);
+ ci->sc_en = 1;
+ return 0;
+}
+
+static int mfld_isp_digital_zoom(struct ci_device *ci, int flag, __s32 * value)
+{
+ u32 zoom;
+
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+ if (flag == 0) {
+ sh_css_get_zoom_factor(&zoom, &zoom);
+ *value = 64 - zoom;
+ }
+
+ if (*value < 0)
+ return -EINVAL;
+
+ if (ci->run_mode == CI_MODE_VIDEO) {
+ zoom = *value;
+ if (zoom >= 64)
+ zoom = 64;
+ zoom = 64 - zoom;
+ sh_css_set_zoom_factor(zoom, zoom);
+ }
+ return 0;
+}
+
+/*
+ * v4l2 ioctls
+ */
+static int mfld_isp_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ int ret = 0;
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_querycaps\n");
+
+ memset(cap, 0, sizeof(struct v4l2_capability));
+ strncpy(cap->driver, DRIVER, strlen(DRIVER));
+ strncpy(cap->card, CARD, strlen(CARD));
+ strncpy(cap->bus_info, BUS_INFO, strlen(BUS_INFO));
+ cap->version = VERSION;
+
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return ret;
+}
+
+static int mfld_isp_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ struct v4l2_format snr_fmt;
+ int ret;
+
+ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupport v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ cropcap->bounds.left = 0;
+ cropcap->bounds.top = 0;
+
+#if (!defined(IMAGE_FROM_FILE) && !defined(IMAGE_FROM_TPG))
+ snr_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ snr_fmt.fmt.pix.height = MFLD_ISP_MAX_HEIGHT;
+ snr_fmt.fmt.pix.width = MFLD_ISP_MAX_WIDTH;
+
+ ret = v4l2_subdev_call(ci->cameras[ci->camera_curr].camera,
+ video, try_fmt, &snr_fmt);
+ if (ret) {
+ mfld_isp_dbg(KERN_ERR, "failed to try_fmt for sensor\n");
+ return ret;
+ }
+ cropcap->bounds.width = snr_fmt.fmt.pix.width;
+ cropcap->bounds.height = snr_fmt.fmt.pix.height;
+ ci->snr_max_width = snr_fmt.fmt.pix.width;
+ ci->snr_max_height = snr_fmt.fmt.pix.height;
+ ci->snr_pixelformat = snr_fmt.fmt.pix.pixelformat;
+#else
+ cropcap->bounds.width = MFLD_ISP_MAX_WIDTH;
+ cropcap->bounds.height = MFLD_ISP_MAX_HEIGHT;
+#endif
+
+ memcpy(&cropcap->defrect, &cropcap->bounds, sizeof(struct v4l2_rect));
+ cropcap->pixelaspect.numerator = 1;
+ cropcap->pixelaspect.denominator = 1;
+ return 0;
+}
+
+static int mfld_isp_g_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupport v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ crop->c.left = 0;
+ crop->c.top = 0;
+
+ if (ci->bayer_downscaling) {
+ crop->c.width = ci->snr_max_width;
+ crop->c.height = ci->snr_max_height;
+ } else {
+ crop->c.width = 0;
+ crop->c.height = 0;
+ }
+
+ return 0;
+}
+
+static int mfld_isp_s_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ struct v4l2_format snr_fmt;
+ int ret;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupport v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ if (!ci->bayer_downscaling) {
+#if (!defined(IMAGE_FROM_FILE) && !defined(IMAGE_FROM_TPG))
+ snr_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ snr_fmt.fmt.pix.height = MFLD_ISP_MAX_HEIGHT;
+ snr_fmt.fmt.pix.width = MFLD_ISP_MAX_WIDTH;
+
+ ret = v4l2_subdev_call(ci->cameras[ci->camera_curr].camera,
+ video, s_fmt, &snr_fmt);
+ if (ret) {
+ mfld_isp_dbg(KERN_ERR, "failed to s_fmt for sensor\n");
+ return ret;
+ }
+ ci->snr_max_width = snr_fmt.fmt.pix.width;
+ ci->snr_max_height = snr_fmt.fmt.pix.height;
+#else
+ ci->snr_max_width = MFLD_ISP_MAX_WIDTH;
+ ci->snr_max_height = MFLD_ISP_MAX_HEIGHT;
+#endif
+ ci->bayer_downscaling = 1;
+ }
+ return 0;
+}
+
+static int mfld_isp_enum_input(struct file *file, void *fh,
+ struct v4l2_input *input)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_enum_input\n");
+
+ if (input->index)
+ return -EINVAL;
+
+ if (!ci->cameras[input->index].camera)
+ return -EINVAL;
+
+ memset(input, 0, sizeof(struct v4l2_input));
+ strcpy(input->name, ci->cameras[input->index].camera->name);
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ return 0;
+}
+
+static int mfld_isp_g_input(struct file *file, void *fh, unsigned int *input)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_g_input\n");
+
+ *input = ci->camera_curr;
+
+ return 0;
+}
+
+static int mfld_isp_s_input(struct file *file, void *fh, unsigned int input)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ struct v4l2_subdev *camera = NULL;
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_s_input\n");
+
+ if (input < 0 || input > 3)
+ return -EINVAL;
+
+ camera = ci->cameras[input].camera;
+ if (!camera)
+ return -EINVAL;
+
+ if (ci->streaming == 1) {
+ mfld_isp_dbg(KERN_ERR, "ISP is still streaming, stop first\n");
+ return -EINVAL;
+ }
+
+ ci->camera_curr = input;
+
+ return 0;
+}
+
+static int mfld_isp_g_std(struct file *file, void *fh, v4l2_std_id * id)
+{
+ return -1;
+}
+
+static int mfld_isp_s_std(struct file *file, void *fh, v4l2_std_id * id)
+{
+ return -1;
+}
+
+static int mfld_isp_enum_fmt_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ __u32 index = f->index;
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_enum_fmt_cap\n");
+
+ /* check buf index */
+ if (index >= SUPPORTED_FMT_NUM) {
+ mfld_isp_dbg(KERN_ERR, "fmt index extends maxiumn"
+ " supported fmts number\n");
+ return -EINVAL;
+ }
+ /* check buf type */
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupported v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ f->pixelformat = SUPPORTED_FMTS[index].pixelformat;
+ memset(f->description, 0, sizeof(char)*32);
+ strncpy(f->description, SUPPORTED_FMTS[index].description,
+ strlen(SUPPORTED_FMTS[index].description));
+
+ return 0;
+}
+
+static int mfld_isp_g_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_g_fmt_cap\n");
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupported v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ memset(f, 0, sizeof(struct v4l2_format));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (ci->width != 0) { /* VIDIOC_S_FMT already called,
+ return fmt setted by app */
+ f->fmt.pix.width = ci->width;
+ f->fmt.pix.height = ci->height;
+ f->fmt.pix.pixelformat = ci->pixelformat;
+ f->fmt.pix.bytesperline = ci->bytesperline;
+ f->fmt.pix.sizeimage = ci->framesize;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+ } else { /* otherwise return default value */
+ f->fmt.pix.width = SUPPORTED_RESOLUTIONS[0].width;
+ f->fmt.pix.height = SUPPORTED_RESOLUTIONS[0].height;
+ f->fmt.pix.pixelformat = SUPPORTED_FMTS[0].pixelformat;
+ f->fmt.pix.bytesperline =
+ get_pixel_depth(f->fmt.pix.pixelformat) *
+ f->fmt.pix.width;
+ f->fmt.pix.sizeimage = f->fmt.pix.height *
+ f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+ }
+
+ return 0;
+}
+
+
+/* This function looks up the closest available resolution. */
+static int mfld_isp_try_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ __u32 out_width = f->fmt.pix.width;
+ __u32 out_height = f->fmt.pix.height;
+ __u32 pixelformat = f->fmt.pix.pixelformat;
+ __u32 in_width, in_height;
+ int ret;
+
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "Wrong v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ mfld_isp_dbg(KERN_DEBUG, "width %d, height %d, format %x\n",
+ out_width, out_height, pixelformat);
+
+#if (!defined(IMAGE_FROM_FILE) && !defined(IMAGE_FROM_TPG))
+ if (get_current_camera(ci) == NULL)
+ return -EINVAL;
+
+ ret = v4l2_subdev_call(ci->cameras[ci->camera_curr].camera,
+ video, try_fmt, f);
+ if (ret)
+ return ret;
+
+ in_width = f->fmt.pix.width;
+ in_height = f->fmt.pix.height;
+
+ mfld_isp_dbg(KERN_DEBUG, "try_fmt, width %d, height %d\n",
+ in_width, in_height);
+#endif
+ if ((in_width < out_width) &&
+ (in_height < out_height)) {
+ out_width = in_width;
+ out_height = in_height;
+ }
+
+ if (out_width < MFLD_WIDTH_RESTRICT ||
+ out_height < MFLD_HEIGHT_RESTRICT)
+ return -EINVAL;
+
+ out_width = (out_width & ~(MFLD_WIDTH_RESTRICT - 1));
+ out_height = (out_height & ~(MFLD_HEIGHT_RESTRICT - 1));
+
+ mfld_isp_dbg(KERN_DEBUG, "Restrict width %d, height %d\n",
+ out_width, out_height);
+
+ f->fmt.pix.width = out_width;
+ f->fmt.pix.height = out_height;
+
+ if (!is_pixelformat_supported(pixelformat)) {
+ mfld_isp_dbg(KERN_ERR, "unsupported pixelformat!\n");
+ /* only support 1 pixelformat now */
+ pixelformat = SUPPORTED_FMTS[0].pixelformat;
+ }
+ f->fmt.pix.pixelformat = pixelformat;
+
+ return 0;
+}
+
+static int mfld_isp_s_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ struct v4l2_format snr_fmt;
+ struct mfld_ci_mipi_camera *mipi_info;
+ struct sh_css_frame_info output_info, raw_output_info;
+ __u32 width = f->fmt.pix.width;
+ __u32 height = f->fmt.pix.height;
+ __u32 pixelformat = f->fmt.pix.pixelformat;
+ __u32 effective_input_width;
+ __u32 effective_input_height;
+ int ret;
+
+ mfld_isp_dbg(KERN_DEBUG, "%s\n", __func__);
+
+ if ((f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (f->type != V4L2_BUF_TYPE_PRIVATE)) {
+ mfld_isp_dbg(KERN_ERR, "Wrong v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ /* Set online processing */
+ if (f->type == V4L2_BUF_TYPE_PRIVATE)
+ ci->online_process = 0;
+ else
+ ci->online_process = 1;
+
+ if (!ci->bayer_downscaling) {
+#if (!defined(IMAGE_FROM_FILE) && !defined(IMAGE_FROM_TPG))
+ snr_fmt = *f;
+ snr_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ snr_fmt.fmt.pix.height += 10;
+ snr_fmt.fmt.pix.width += 8;
+
+ ret = v4l2_subdev_call(ci->cameras[ci->camera_curr].camera,
+ video, s_fmt, &snr_fmt);
+ if (ret) {
+ mfld_isp_dbg(KERN_ERR,
+ "call s_fmt for sensor failed\n");
+ return ret;
+ }
+
+ ci->snr_width = snr_fmt.fmt.pix.width;
+ ci->snr_height = snr_fmt.fmt.pix.height;
+ ci->snr_pixelformat = snr_fmt.fmt.pix.pixelformat;
+
+ mfld_isp_dbg(KERN_DEBUG,
+ "snr_width %d, snr_height %d, pixelfmt %d\n",
+ ci->snr_width, ci->snr_height, ci->snr_pixelformat);
+
+ if (ci->snr_width < MFLD_WIDTH_RESTRICT ||
+ ci->snr_height < MFLD_HEIGHT_RESTRICT)
+ return -EINVAL;
+#endif
+ } else {
+ ci->snr_width = ci->snr_max_width;
+ ci->snr_height = ci->snr_max_height;
+ }
+
+ width = (width & ~(MFLD_WIDTH_RESTRICT - 1));
+ height = (height & ~(MFLD_HEIGHT_RESTRICT - 1));
+
+#if (!defined(IMAGE_FROM_FILE) && !defined(IMAGE_FROM_TPG))
+ if ((ci->snr_width < width) &&
+ (ci->snr_height < height)) {
+ width = ci->snr_width;
+ height = ci->snr_height;
+ }
+
+ if (((ci->snr_width - 8) > width) &&
+ ((ci->snr_height - 10) > height) &&
+ (ci->bayer_downscaling)) {
+ mfld_isp_dbg(KERN_DEBUG, "Enable Bayer Downscaling\n");
+ effective_input_width = ci->snr_width - 8;
+ effective_input_height = ci->snr_height - 10;
+
+ /*effective_input_width = 1280;*/
+ /*effective_input_height = 720;*/
+ } else {
+ effective_input_width = width;
+ effective_input_height = height;
+ }
+#endif
+
+ ci->pixelformat = pixelformat;
+ ci->sh_pixelformat = v4l2_fmt_to_sh_fmt(ci->pixelformat);
+
+#ifdef IMAGE_FROM_FILE
+ mfld_isp_dbg(KERN_DEBUG, "alloc IMAGE data for ISP test.\n");
+ mfld_isp_dbg(KERN_DEBUG,
+ "The size we expect %d\n", ci->width * ci->height * 2);
+ mfld_isp_dbg(KERN_INFO, "The size we got %d\n", g_input_file_size);
+ ci->image_file = g_input_file_data;
+ if (!ci->image_file) {
+ mfld_isp_dbg(KERN_ERR, "Load image file failed.\n");
+ return -1;
+ }
+ if ((ci->width < IMAGE_W) && (ci->height < IMAGE_H)) {
+ ci->input_file = vmalloc(ci->width * ci->height * 2);
+ if (!ci->input_file) {
+ mfld_isp_dbg(KERN_ERR,
+ "Failed to alloc input_file memory\n");
+ return -1;
+ }
+
+ mfld_isp_resize_image((unsigned short *)ci->image_file,
+ (unsigned short *)ci->input_file, 0, 0,
+ IMAGE_W, IMAGE_H, ci->width, ci->height);
+ }
+#endif
+
+#if (!defined(IMAGE_FROM_FILE) && !defined(IMAGE_FROM_TPG))
+ mfld_isp_dbg(KERN_DEBUG, "snr_width %d, snr_height %d\n",
+ ci->snr_width, ci->snr_height);
+ sh_css_input_set_resolution(ci->snr_width, ci->snr_height);
+
+ mfld_isp_dbg(KERN_DEBUG, "Setup sensor specifc configure for MIPI\n");
+ mipi_info = to_sensor_mipi_info(ci->cameras[ci->camera_curr].camera);
+ if (mipi_info) {
+ mfld_isp_dbg(KERN_DEBUG,
+ "MIPI info from camera sensor: bayer %d"
+ " format %d\n", mipi_info->raw_bayer_order,
+ mipi_info->input_format);
+ mfld_isp_dbg(KERN_DEBUG, "sensor mipilane - %d\n",
+ mipi_info->num_of_lane);
+ sh_css_input_set_bayer_order(mipi_info->raw_bayer_order);
+ sh_css_input_set_format(mipi_info->input_format);
+ sh_css_input_configure_port(mipi_info->port,
+ mipi_info->num_of_lane,
+ 0xffff4);
+
+ } else {
+ /*sh_css_input_set_bayer_order(sh_css_bayer_order_rggb);*/
+ mfld_isp_dbg(KERN_DEBUG, "no sensor config info\n");
+ sh_css_input_set_bayer_order(sh_css_bayer_order_bggr);
+ /*sh_css_input_set_bayer_order(sh_css_bayer_order_grbg); */
+ sh_css_input_set_format(sh_css_input_format_raw_10);
+#ifdef MIPI_LANE_4
+ mfld_isp_dbg(KERN_DEBUG, "MIPI 4 lane\n");
+ sh_css_input_configure_port(sh_css_mipi_port_4lane, 4, 0xffff4);
+#endif
+#ifdef MIPI_LANE_2
+ mfld_isp_dbg(KERN_INFO, "MIPI 2 lane\n");
+ sh_css_input_configure_port(sh_css_mipi_port_4lane, 2, 0xffff4);
+#endif
+#ifdef MIPI_LANE_1
+ mfld_isp_dbg(KERN_INFO, "MIPI 1 lane\n");
+ sh_css_input_configure_port(sh_css_mipi_port_4lane, 1, 0xffff4);
+#endif
+ }
+#else
+ sh_css_input_set_resolution(width, height);
+
+#endif
+
+ return_on_css_error(sh_css_input_set_effective_resolution
+ (effective_input_width, effective_input_height));
+
+ switch (ci->run_mode) {
+ case CI_MODE_PREVIEW:
+ return_on_css_error(sh_css_preview_configure_output
+ (width, height, ci->sh_pixelformat));
+ return_on_css_error(sh_css_preview_set_isp_parameters
+ (ci->isp_params));
+ return_on_css_error(sh_css_preview_get_output_frame_info
+ (&output_info));
+ break;
+ case CI_MODE_VIDEO:
+ return_on_css_error(sh_css_video_configure_viewfinder
+ (vf_width, vf_height, vf_format));
+ return_on_css_error(sh_css_video_configure_output
+ (width, height, ci->sh_pixelformat));
+ return_on_css_error(sh_css_video_set_isp_parameters
+ (ci->isp_params));
+ return_on_css_error(sh_css_video_get_output_frame_info
+ (&output_info));
+ break;
+ default:
+#ifdef GDC_EN
+ sh_css_capture_set_mode(sh_css_capture_mode_advanced);
+#endif
+
+#ifdef XNR_EN
+ sh_css_capture_enable_xnr(1);
+#endif
+
+ if (ci->sh_pixelformat == sh_css_frame_format_vraw16 ||
+ ci->sh_pixelformat == sh_css_frame_format_raw16 ||
+ ci->sh_pixelformat == sh_css_frame_format_raw8) {
+ mfld_isp_dbg(KERN_WARNING, "set capture raw mode\n");
+ return_on_css_error(sh_css_capture_set_mode
+ (sh_css_capture_mode_raw));
+ }
+
+ return_on_css_error(sh_css_capture_enable_online
+ (ci->online_process));
+
+ return_on_css_error(sh_css_capture_configure_viewfinder
+ (vf_width, vf_height, vf_format));
+ return_on_css_error(sh_css_capture_configure_output
+ (width, height, ci->sh_pixelformat));
+ return_on_css_error(sh_css_capture_set_isp_parameters
+ (ci->isp_params));
+
+ return_on_css_error(sh_css_capture_get_output_frame_info
+ (&output_info));
+
+ if (!ci->online_process)
+ return_on_css_error
+ (sh_css_capture_get_output_raw_frame_info
+ (&raw_output_info));
+
+ if (ci->run_mode != CI_MODE_STILL_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR,
+ "Need to set the running mode first\n");
+ ci->run_mode = CI_MODE_STILL_CAPTURE;
+ }
+ break;
+ }
+
+ ci->width = width;
+ ci->height = height;
+ ci->pixeldepth = get_pixel_depth(pixelformat);
+ ci->bytesperline = (ci->pixeldepth * output_info.padded_width) / 8;
+ ci->framesize = height * ci->bytesperline;
+ ci->imagesize = PAGE_ALIGN(ci->framesize);
+ f->fmt.pix.sizeimage = ci->imagesize;
+ f->fmt.pix.width = width;
+ f->fmt.pix.height = height;
+ mfld_isp_dbg(KERN_DEBUG, "raw width %d, raw height %d\n",
+ raw_output_info.padded_width, raw_output_info.height);
+ f->fmt.pix.priv = PAGE_ALIGN(raw_output_info.padded_width *
+ raw_output_info.height * 2);
+
+ mfld_isp_dbg(KERN_DEBUG, "width = %d, height = %d, fourcc = %s\n",
+ ci->width, ci->height,
+ get_ci_format(ci->pixelformat)->description);
+
+ mfld_isp_dbg(KERN_DEBUG, "pixeldepth = %d, frame_size = %d\n",
+ ci->pixeldepth, ci->framesize);
+ mfld_isp_dbg(KERN_DEBUG, "raw size priv = %d\n", f->fmt.pix.priv);
+ return 0;
+}
+
+static int mfld_isp_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *arg)
+{
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_enum_framesizes\n");
+
+ if (arg->index < 0 || arg->index >= SUPPORTED_RESOLUTION_NUM)
+ return -EINVAL;
+
+ if (!is_pixelformat_supported(arg->pixel_format))
+ return -EINVAL;
+
+ arg->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ arg->discrete.width = SUPPORTED_RESOLUTIONS[arg->index].width;
+ arg->discrete.height = SUPPORTED_RESOLUTIONS[arg->index].height;
+
+ return 0;
+}
+
+static int mfld_isp_enum_frameintervals(struct file *file, void *fh,
+ struct v4l2_frmivalenum *arg)
+{
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_enum_frameintervals\n");
+
+ if (arg->index < 0 || arg->index >= SUPPORTED_RESOLUTION_NUM)
+ return -EINVAL;
+
+ if (!is_pixelformat_supported(arg->pixel_format))
+ return -EINVAL;
+
+ if (!is_resolution_supported(arg->width, arg->height))
+ return -EINVAL;
+
+ arg->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ arg->discrete.numerator = 1;
+ arg->discrete.denominator = 30;
+
+ return 0;
+}
+
+static void add_frame_to_queue(struct fifo *queue, int frame)
+{
+ queue->data[queue->back] = frame;
+ queue->back = (queue->back + 1) % (CI_MAX_BUF_NUM + 1);
+}
+
+static int frame_queue_empty(struct fifo *queue)
+{
+ return queue->front == queue->back;
+}
+
+static int remove_frame_from_queue(struct fifo *queue)
+{
+ int frame;
+
+ if (frame_queue_empty(queue))
+ return -1;
+
+ frame = queue->data[queue->front];
+ queue->front = (queue->front + 1) % (CI_MAX_BUF_NUM + 1);
+ return frame;
+}
+
+static void init_frame_queue(struct fifo *queue)
+{
+ int i;
+ for (i = 0; i < CI_MAX_BUF_NUM; i++) {
+ queue->data[i] = -1;
+ queue->info[i].state = S_UNUSED;
+ queue->info[i].flags = 0;
+ }
+ queue->front = 0;
+ queue->back = 0;
+}
+
+static int mfld_isp_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *req)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ int i, ret = 0;
+ struct sh_css_frame_info out_info, vf_info;
+ struct sh_css_frame *frame;
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_reqbufs %d\n", req->count);
+
+ if (req->count == 0) {
+ if (ci->buf_allocated) {
+ for (i = 0; i < ci->bufnum; i++)
+ free_buffer(ci->imagebuf[i]);
+ kfree(ci->imagebuf);
+ ci->imagebuf = NULL;
+ if (ci->vf_frame) {
+ sh_css_frame_free(ci->vf_frame);
+ ci->vf_frame = NULL;
+ }
+ ci->buf_allocated = 0;
+ }
+ return 0;
+ }
+
+ if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupported v4l2 buf type\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if ((req->memory != V4L2_MEMORY_MMAP) &&
+ (req->memory != V4L2_MEMORY_USERPTR)) {
+ mfld_isp_dbg(KERN_ERR, "unsupported v4l2 memory type\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ req->count = ci->bufnum = MIN(req->count, CI_MAX_BUF_NUM);
+
+ init_frame_queue(&ci->buf_queue);
+
+ /* prepare buffer handles for buffers */
+ ci->imagebuf = kmalloc(sizeof(struct ci_buffer *)*ci->bufnum,
+ GFP_KERNEL);
+ if (ci->imagebuf == NULL) {
+ mfld_isp_dbg(KERN_ERR, "out of memory\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ for (i = 0; i < ci->bufnum; i++)
+ ci->imagebuf[i] = NULL;
+
+ /*Allocate the frame buffer to be used */
+ mfld_isp_dbg(KERN_DEBUG, "allocate_frame ... ");
+ switch (ci->run_mode) {
+ case CI_MODE_STILL_CAPTURE:
+ if (ci->sh_pixelformat != sh_css_frame_format_vraw16 &&
+ ci->sh_pixelformat != sh_css_frame_format_raw8 &&
+ ci->sh_pixelformat != sh_css_frame_format_raw16) {
+ goto_on_css_error
+ (sh_css_capture_get_viewfinder_frame_info
+ (&vf_info), ret, error);
+ goto_on_css_error
+ (sh_css_frame_allocate_from_info
+ (&ci->vf_frame, &vf_info), ret,
+ error);
+ }
+ goto_on_css_error(sh_css_capture_get_output_frame_info
+ (&out_info), ret, error);
+ break;
+ case CI_MODE_VIDEO:
+ goto_on_css_error(sh_css_video_get_viewfinder_frame_info
+ (&vf_info), ret, error);
+ goto_on_css_error(sh_css_video_get_output_frame_info(&out_info),
+ ret, error);
+ goto_on_css_error(sh_css_frame_allocate_from_info
+ (&ci->vf_frame, &vf_info), ret, error);
+ break;
+ case CI_MODE_PREVIEW:
+ goto_on_css_error(sh_css_preview_get_output_frame_info
+ (&out_info), ret, error);
+ break;
+ }
+
+ ci->buf_type = req->memory;
+
+ /*
+ * for user pointer type, buffers are not really allcated here,
+ * buffers are setup in QBUF operation through v4l2_buffer structure
+ */
+ if (req->memory == V4L2_MEMORY_USERPTR) {
+ mfld_isp_dbg(KERN_DEBUG, "user pointer, not really allocate"
+ " memory here.\n");
+ return 0;
+ }
+
+ /* allocate output frames, wrap them and store in buffer. */
+ for (i = 0; i < ci->bufnum; i++) {
+ mfld_isp_dbg(KERN_ERR, "%s, %d\n", __func__, __LINE__);
+ goto_on_css_error(sh_css_frame_allocate_from_info(&frame,
+ &out_info),
+ ret, error);
+ ci->imagebuf[i] = alloc_buffer(frame);
+ if (!ci->imagebuf[i]) {
+ mfld_isp_dbg(KERN_ERR, "%s, %d\n", __func__, __LINE__);
+ ret = -ENOMEM;
+ goto error;
+ }
+ }
+
+ ci->buf_allocated = 1;
+
+ mfld_isp_dbg(KERN_DEBUG, "request buffer done\n");
+
+ return 0;
+error:
+ if (ci->imagebuf) {
+ for (i = 0; i < ci->bufnum; i++) {
+ if (ci->imagebuf[i])
+ free_buffer(ci->imagebuf[i]);
+ }
+ kfree(ci->imagebuf);
+ }
+ if (ci->vf_frame)
+ sh_css_frame_free(ci->vf_frame);
+
+ return ret;
+}
+
+static int mfld_isp_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ int index = buf->index;
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_querybuf: index = %d\n", index);
+
+ if (index < 0 || index >= ci->bufnum) {
+ mfld_isp_dbg(KERN_ERR, "wrong index, only support 1 buf now\n");
+ return -EINVAL;
+ }
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupported v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ if (ci->imagebuf == NULL) {
+ mfld_isp_dbg(KERN_ERR, "buffer not allocated\n");
+ return -EINVAL;
+ }
+
+ memset(buf, 0, sizeof(*buf));
+ buf->index = index;
+ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf->length = ci->imagesize;
+ buf->bytesused = 0; /* this should be given in VIDIOC_DQBUF */
+ buf->memory = ci->buf_type;
+
+ mfld_isp_dbg(KERN_DEBUG, "ci_querybuf: length = %d, , index=%d\n",
+ buf->length, buf->index);
+
+ switch (buf->memory) {
+ case V4L2_MEMORY_MMAP:
+ buf->m.offset = index * ci->imagesize;
+ break;
+ case V4L2_MEMORY_USERPTR:
+ mfld_isp_dbg(KERN_DEBUG, "cannot query USERPTR type buf.\n");
+ break;
+ default:
+ mfld_isp_dbg(KERN_ERR, "invalid buf type.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mfld_isp_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+
+ __u32 index;
+ __u32 length;
+ unsigned long userptr;
+ __u32 pgnr;
+
+ __u32 width, height;
+
+ int err = 0;
+ struct sh_css_frame_info out_info;
+ struct sh_css_frame *handle;
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_qbuf\n");
+
+ /* do nothing now */
+ index = buf->index;
+ length = buf->length;
+ userptr = buf->m.userptr;
+
+ width = ci->width;
+ height = ci->height;
+
+ if (index >= ci->bufnum) {
+ mfld_isp_dbg(KERN_ERR, "buf index out of range\n");
+ return -EINVAL;
+ }
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupported v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ if (ci->imagebuf == NULL) {
+ mfld_isp_dbg(KERN_ERR, "buffer not allocated\n");
+ return -EINVAL;
+ }
+
+ if (ci->imagebuf[index] &&
+ (ci->imagebuf[index]->flags & V4L2_BUF_FLAG_QUEUED)) {
+ mfld_isp_dbg(KERN_ERR, "buffer %d already in queue\n", index);
+ return -EINVAL;
+ }
+
+ switch (buf->memory) {
+ case V4L2_MEMORY_MMAP:
+ if (!ci->buf_allocated) {
+ mfld_isp_dbg(KERN_ERR, "buffers not allocated.\n");
+ return -EINVAL;
+ }
+ ci->imagebuf[index]->idx = index;
+ break;
+ case V4L2_MEMORY_USERPTR:
+ if ((length & (~(PAGE_SIZE - 1))) != length)
+ mfld_isp_dbg(KERN_ALERT, "user buffer's length"
+ " not page-aligned.\n");
+
+ pgnr = (length + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+
+ mfld_isp_dbg(KERN_DEBUG, "buffer %d: addr = 0x%x,"
+ " length = %d, pgnr = %d\n", index,
+ (unsigned int)userptr, length, pgnr);
+
+ if ((ci->imagebuf[index]) &&
+ (ci->imagebuf[index]->userptr) &&
+ (ci->imagebuf[index]->userptr == userptr))
+ break;
+
+ switch (ci->run_mode) {
+ case CI_MODE_STILL_CAPTURE:
+ err = sh_css_capture_get_output_frame_info(&out_info);
+ break;
+ case CI_MODE_PREVIEW:
+ err = sh_css_preview_get_output_frame_info(&out_info);
+ break;
+ case CI_MODE_VIDEO:
+ err = sh_css_video_get_output_frame_info(&out_info);
+ break;
+ }
+ if (err) {
+ mfld_isp_dbg(KERN_ERR, "get_output_frame_info error\n");
+ return -1;
+ }
+
+ if ((ci->imagebuf[index]) &&
+ (ci->imagebuf[index]->userptr) &&
+ (ci->imagebuf[index]->userptr != userptr)) {
+ sh_css_frame_free(ci->imagebuf[index]->handle);
+ free_buffer(ci->imagebuf[index]);
+ }
+
+ mfld_isp_dbg(KERN_DEBUG, "%s, %d\n", __func__, __LINE__);
+ hrt_isp_css_mm_set_user_ptr(userptr, pgnr);
+ sh_css_frame_allocate_from_info(&handle, &out_info);
+ hrt_isp_css_mm_set_user_ptr(0, 0);
+ mfld_isp_dbg(KERN_DEBUG, "%s, %d\n", __func__, __LINE__);
+ if (handle == NULL) {
+ mfld_isp_dbg(KERN_ERR, "Error to allocate"
+ " frame for capture\n");
+ return -1;
+ }
+
+ ci->imagebuf[index] = alloc_user_buffer(handle, userptr,
+ pgnr, index);
+
+ break;
+ default:
+ mfld_isp_dbg(KERN_ERR, "unsupported memory type...\n");
+ return -EINVAL;
+ }
+
+ ci->buf_queue.info[index].state = S_QUEUED;
+ add_frame_to_queue(&ci->buf_queue, index);
+
+ buf->flags &= ~V4L2_BUF_FLAG_DONE;
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+ buf->flags |= V4L2_BUF_FLAG_MAPPED;
+
+ return 0;
+}
+
+static int mfld_isp_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ struct ci_buffer *ci_buf;
+ unsigned int dvs_envelope_w, dvs_envelope_h;
+ struct sh_css_frame *raw_frame;
+ u32 msg_ret;
+ u32 term_en_count;
+ int ret;
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_dqbuf\n");
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupported v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ if (ci->imagebuf == NULL) {
+ mfld_isp_dbg(KERN_ERR, "buffer not allocated\n");
+ return -EINVAL;
+ }
+
+
+ buf->index = remove_frame_from_queue(&ci->buf_queue);
+
+ mfld_isp_dbg(KERN_DEBUG, "dqueue 1 buf from buffer queue index %d...\n",
+ buf->index);
+ ci_buf = ci->imagebuf[buf->index];
+ if (ci_buf == NULL) {
+ mfld_isp_dbg(KERN_ERR, "no available buffer in buffer queue\n");
+ return -EINVAL;
+ }
+
+ if (buf->memory != ci_buf->buf_type) {
+ mfld_isp_dbg(KERN_ERR, "buffer type is not the same as created"
+ " buffer type.\n");
+ return -EINVAL;
+ }
+
+ /* fill user space struct */
+ buf->index = ci_buf->idx;
+ buf->bytesused = ci->framesize;
+ buf->length = ci->imagesize;
+
+ if (buf->memory == V4L2_MEMORY_MMAP) {
+ buf->m.offset = ci_buf->idx * ci->imagesize;
+ } else if (buf->memory == V4L2_MEMORY_USERPTR) {
+ buf->m.userptr = ci_buf->userptr;
+ } else {
+ mfld_isp_dbg(KERN_ERR, "unsupported buffer type.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Kai:
+ *
+ * setup output_frame here.
+ */
+ ci->regular_output_frame = ci_buf->handle;
+
+#ifdef PUNIT_CAMERA_BUSY
+ u32 msg_ret;
+ /* Set camera_busy bit in Punit */
+ msg_ret = MSG_READ32(0x04, 0x72);
+ msg_ret |= 0x100;
+ MSG_WRITE32(0x04, 0x72, msg_ret);
+#endif
+ /* for 4-lane configuration */
+ msg_ret = MSG_READ32(0x09, 0x3);
+ term_en_count = (msg_ret & 0x00f00000) >> 20;
+ mfld_isp_dbg(KERN_DEBUG, "MSG_RET = %x, TERM_EN_COUNT = %x\n",
+ msg_ret, term_en_count);
+ if (term_en_count != 0xF) {
+ term_en_count = 0xF;
+ msg_ret = (msg_ret & 0xff0fffff) |
+ ((term_en_count & 0xf) << 20);
+ MSG_WRITE32(0x09, 0x3, msg_ret);
+ }
+
+ /* for 1-lane configuration */
+ msg_ret = MSG_READ32(0x09, 0x3);
+ term_en_count = (msg_ret & 0x000f0000) >> 16;
+ mfld_isp_dbg(KERN_DEBUG, "MSG_RET = %x, TERM_EN_COUNT = %x\n",
+ msg_ret, term_en_count);
+ if (term_en_count != 0xF) {
+ term_en_count = 0xF;
+ msg_ret = (msg_ret & 0xfff0ffff) |
+ ((term_en_count & 0xf) << 16);
+ MSG_WRITE32(0x09, 0x3, msg_ret);
+ }
+
+
+ switch (ci->run_mode) {
+ case CI_MODE_STILL_CAPTURE:
+ sh_css_capture_start(ci->regular_output_frame, ci->vf_frame);
+ break;
+ case CI_MODE_PREVIEW:
+ sh_css_preview_start(ci->regular_output_frame);
+ break;
+ /*case CI_MODE_VIDEO: */
+ /*sh_css_video_start(NULL, ci->regular_output_frame,
+ * ci->vf_frame); */
+ /*break; */
+ }
+
+ if (ci->run_mode == CI_MODE_VIDEO) {
+ if (ci->video_dis_en) {
+ dvs_envelope_w = ci->width / 10;
+ dvs_envelope_h = ci->height / 10;
+ sh_css_video_set_dis_vector(ci->dis_x, ci->dis_y);
+ sh_css_video_set_dis_envelope(dvs_envelope_w,
+ dvs_envelope_h);
+ }
+ sh_css_video_start(NULL, ci->regular_output_frame,
+ ci->vf_frame);
+ }
+#if (!defined(IMAGE_FROM_TPG))
+ mfld_isp_dbg(KERN_DEBUG, "Stream on camera sensor\n");
+ /* stream on the sensor */
+ if (ci->streaming != 1) {
+ ret = v4l2_subdev_call(ci->cameras[ci->camera_curr].camera,
+ video, s_stream, 1);
+ if (ret) {
+ mfld_isp_dbg(KERN_ERR, "stream on sensor err.\n");
+ return ret;
+ }
+ ci->streaming = 1;
+ }
+#endif
+
+ sh_css_wait_for_completion();
+
+ buf->flags &= ~V4L2_BUF_FLAG_DONE;
+ buf->flags &= ~V4L2_BUF_FLAG_QUEUED;
+ buf->flags |= V4L2_BUF_FLAG_MAPPED;
+
+ if (ci->online_process == 0) {
+ raw_frame = sh_css_get_raw_frame();
+ mfld_isp_dbg(KERN_ERR, "The RAW virtual address is %x\n",
+ (unsigned int)raw_frame);
+ sh_css_convert_raw_frame(raw_frame, ci->width,
+ (ci->height + 8));
+ }
+
+#ifdef PUNIT_CAMERA_BUSY
+ /* Free camera_busy bit */
+ msg_ret = MSG_READ32(0x04, 0x72);
+ msg_ret &= ~0x100;
+ MSG_WRITE32(0x04, 0x72, msg_ret);
+#endif
+
+ return 0;
+}
+
+static int mfld_isp_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_streamon\n");
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupported v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ if (ci->imagebuf == NULL) {
+ mfld_isp_dbg(KERN_ERR, "buffer not allocated\n");
+ return -EINVAL;
+ }
+
+#if (!defined(IMAGE_FROM_TPG))
+ /*mfld_isp_dbg(KERN_INFO, "Stream on camera sensor\n");*/
+ /*[> stream on the sensor <]*/
+ /*ret = v4l2_subdev_call(ci->cameras[ci->camera_curr].camera,*/
+ /*video, s_stream, 1);*/
+ /*if (ret) {*/
+ /*mfld_isp_dbg(KERN_ERR, "stream on sensor err.\n");*/
+ /*return ret;*/
+ /*}*/
+#endif
+
+ return 0;
+}
+
+static int mfld_isp_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_streamoff\n");
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupported v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ if (!ci->streaming)
+ return -1;
+
+ ci->streaming = 0;
+
+#if (!defined(IMAGE_FROM_TPG))
+ v4l2_subdev_call(ci->cameras[ci->camera_curr].camera, video,
+ s_stream, 0);
+#endif
+
+ return 0;
+}
+
+static int mfld_isp_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *control)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ int i, ret = -EINVAL;
+
+ for (i = 0; i < SUPPORTED_CTRL_NUM; i++) {
+ if (ci_v4l2_controls[i].id == control->id) {
+ ret = 0;
+ goto next;
+ }
+ }
+
+next:
+ if (ret)
+ return ret;
+
+ switch (control->id) {
+ case V4L2_CID_COLORFX:
+ ret = mfld_isp_color_effect(ci, 0, &control->value);
+ break;
+ case V4L2_CID_ATOMISP_BAD_PIXEL_DETECTION:
+ ret = mfld_isp_bad_pixel(ci, 0, &control->value);
+ break;
+ case V4L2_CID_ATOMISP_POSTPROCESS_GDC_CAC:
+ ret = mfld_isp_gdc_cac(ci, 0, &control->value);
+ break;
+ case V4L2_CID_ATOMISP_VIDEO_STABLIZATION:
+ ret = mfld_isp_video_stable(ci, 0, &control->value);
+ break;
+ case V4L2_CID_ATOMISP_FIXED_PATTERN_NR:
+ ret = mfld_isp_fixed_pattern(ci, 0, &control->value);
+ break;
+ case V4L2_CID_ATOMISP_FALSE_COLOR_CORRECTION:
+ ret = mfld_isp_false_color(ci, 0, &control->value);
+ break;
+ case V4L2_CID_ATOMISP_SHADING_CORRECTION:
+ ret = mfld_isp_shading_correction(ci, 0, &control->value);
+ break;
+ }
+
+ /* Right now we leave this contrl function null */
+ control->value = 0;
+ return ret;
+}
+
+static int mfld_isp_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *control)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ int i, ret = -EINVAL;
+
+ for (i = 0; i < SUPPORTED_CTRL_NUM; i++) {
+ if (ci_v4l2_controls[i].id == control->id) {
+ ret = 0;
+ goto next;
+ }
+ }
+
+next:
+ if (ret)
+ return ret;
+
+ switch (control->id) {
+ case V4L2_CID_COLORFX:
+ ret = mfld_isp_color_effect(ci, 1, &control->value);
+ break;
+ case V4L2_CID_ATOMISP_BAD_PIXEL_DETECTION:
+ ret = mfld_isp_bad_pixel(ci, 1, &control->value);
+ break;
+ case V4L2_CID_ATOMISP_POSTPROCESS_GDC_CAC:
+ ret = mfld_isp_gdc_cac(ci, 1, &control->value);
+ break;
+ case V4L2_CID_ATOMISP_VIDEO_STABLIZATION:
+ ret = mfld_isp_video_stable(ci, 1, &control->value);
+ break;
+ case V4L2_CID_ATOMISP_FIXED_PATTERN_NR:
+ ret = mfld_isp_fixed_pattern(ci, 1, &control->value);
+ break;
+ case V4L2_CID_ATOMISP_FALSE_COLOR_CORRECTION:
+ ret = mfld_isp_false_color(ci, 1, &control->value);
+ break;
+ case V4L2_CID_ATOMISP_SHADING_CORRECTION:
+ ret = mfld_isp_shading_correction(ci, 1, &control->value);
+ break;
+ }
+ /* Right now we leave this contrl function null */
+ return ret;
+}
+
+static int mfld_isp_queryctl(struct file *file, void *fh,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+ int ret = -EINVAL;
+
+ if (qc->id & V4L2_CTRL_FLAG_NEXT_CTRL)
+ return ret;
+
+ for (i = 0; i < SUPPORTED_CTRL_NUM; i++) {
+ if (ci_v4l2_controls[i].id == qc->id) {
+ memcpy(qc, &ci_v4l2_controls[i],
+ sizeof(struct v4l2_queryctrl));
+ qc->reserved[0] = 0;
+ qc->flags = V4L2_CTRL_FLAG_DISABLED;
+ ret = 0;
+ goto exit;
+ }
+ }
+exit:
+ return ret;
+}
+
+static int mfld_isp_g_ext_ctrls(struct file *file, void *fh,
+ struct v4l2_ext_controls *c)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ struct v4l2_control ctrl;
+ int i;
+ int ret = 0;
+
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ ret = mfld_isp_g_ctrl(file, fh, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (ret) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return ret;
+ }
+
+ if (c->ctrl_class == V4L2_CTRL_CLASS_CAMERA) {
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ switch (ctrl.id) {
+ case V4L2_CID_EXPOSURE_ABSOLUTE:
+ case V4L2_CID_ISO_ABSOLUTE:
+ case V4L2_CID_APERTURE_ABSOLUTE:
+ case V4L2_CID_SS_EXPOSURE_ABSOLUTE:
+ case V4L2_CID_SS_ISO_ABSOLUTE:
+ case V4L2_CID_SS_APERTURE_ABSOLUTE:
+ ret =
+ v4l2_subdev_call(ci->cameras
+ [ci->camera_curr].camera,
+ core, g_ctrl, &ctrl);
+ break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ case V4L2_CID_FOCUS_AUTO:
+ if (ci->cameras[ci->camera_curr].type ==
+ CAMERA_SENSOR_MOTOR)
+ ret =
+ v4l2_subdev_call(ci->cameras
+ [ci->camera_curr].motor,
+ core, g_ctrl,
+ &ctrl);
+ else
+ ret =
+ v4l2_subdev_call(ci->cameras
+ [ci->camera_curr].camera,
+ core, g_ctrl,
+ &ctrl);
+ break;
+ case V4L2_CID_FLASH_DELAY:
+ case V4L2_CID_FLASH_DURATION:
+ case V4L2_CID_FLASH_STROBE:
+ case V4L2_CID_FLASH_TIMEOUT:
+ case V4L2_CID_FLASH_INTENSITY:
+ case V4L2_CID_TORCH_INTENSITY:
+ case V4L2_CID_INDICATOR_INTENSITY:
+ if (ci->xenon_flash)
+ ret = v4l2_subdev_call(ci->xenon_flash,
+ core, g_ctrl,
+ &ctrl);
+ else
+ ret = v4l2_subdev_call(ci->led_flash,
+ core, g_ctrl,
+ &ctrl);
+ break;
+ case V4L2_CID_ZOOM_ABSOLUTE:
+ /* add digital zoom code here */
+ ret = mfld_isp_digital_zoom(ci, 0, &ctrl.value);
+ break;
+ }
+ c->controls[i].value = ctrl.value;
+ if (ret) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return ret;
+ }
+ return -EINVAL;
+}
+
+static int mfld_isp_s_ext_ctrls(struct file *file, void *fh,
+ struct v4l2_ext_controls *c)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ struct v4l2_control ctrl;
+ int i;
+ int ret = 0;
+
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ ret = mfld_isp_s_ctrl(file, fh, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (ret) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return ret;
+ }
+
+ if (c->ctrl_class == V4L2_CTRL_CLASS_CAMERA) {
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ switch (ctrl.id) {
+ case V4L2_CID_EXPOSURE_ABSOLUTE:
+ case V4L2_CID_ISO_ABSOLUTE:
+ case V4L2_CID_APERTURE_ABSOLUTE:
+ case V4L2_CID_SS_EXPOSURE_ABSOLUTE:
+ case V4L2_CID_SS_ISO_ABSOLUTE:
+ case V4L2_CID_SS_APERTURE_ABSOLUTE:
+ ret =
+ v4l2_subdev_call(ci->cameras
+ [ci->camera_curr].camera,
+ core, s_ctrl, &ctrl);
+ break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ case V4L2_CID_FOCUS_AUTO:
+ if (ci->cameras[ci->camera_curr].type ==
+ CAMERA_SENSOR_MOTOR)
+ ret =
+ v4l2_subdev_call(ci->cameras
+ [ci->camera_curr].motor,
+ core, s_ctrl,
+ &ctrl);
+ else
+ ret =
+ v4l2_subdev_call(ci->cameras
+ [ci->camera_curr].camera,
+ core, s_ctrl,
+ &ctrl);
+ break;
+ case V4L2_CID_FLASH_DELAY:
+ case V4L2_CID_FLASH_DURATION:
+ case V4L2_CID_FLASH_STROBE:
+ case V4L2_CID_FLASH_TIMEOUT:
+ case V4L2_CID_FLASH_INTENSITY:
+ case V4L2_CID_TORCH_INTENSITY:
+ case V4L2_CID_INDICATOR_INTENSITY:
+ if (ci->xenon_flash)
+ ret = v4l2_subdev_call(ci->xenon_flash,
+ core, s_ctrl,
+ &ctrl);
+ else
+ ret = v4l2_subdev_call(ci->led_flash,
+ core, s_ctrl,
+ &ctrl);
+ break;
+ case V4L2_CID_ZOOM_ABSOLUTE:
+ ret = mfld_isp_digital_zoom(ci, 1,
+ &ctrl.value);
+ /* add digital zoom code here */
+ break;
+ }
+ c->controls[i].value = ctrl.value;
+ if (ret) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return ret;
+ }
+ return -EINVAL;
+}
+
+static int mfld_isp_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *parm)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_g_parm\n");
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupport v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ parm->parm.capture.capturemode = ci->run_mode;
+
+ return 0;
+}
+
+static int mfld_isp_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *parm)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ int ret = 0;
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_s_parm\n");
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mfld_isp_dbg(KERN_ERR, "unsupport v4l2 buf type\n");
+ return -EINVAL;
+ }
+
+ ci->run_mode = parm->parm.capture.capturemode;
+ mfld_isp_dbg(KERN_DEBUG, "Set ISP running mode to %d\n", ci->run_mode);
+
+ return ret;
+}
+
+static long mfld_isp_vidioc_default(struct file *file, void *fh,
+ int cmd, void *arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+
+ switch (cmd) {
+ case ATOMISP_IOC_G_XNR:
+ return mfld_isp_xnr(ci, 0, arg);
+
+ case ATOMISP_IOC_S_XNR:
+ return mfld_isp_xnr(ci, 1, arg);
+
+ case ATOMISP_IOC_G_BAYER_NR:
+ return mfld_isp_bayer_nr(ci, 0,
+ (struct sh_css_isp_nr_config *)arg);
+
+ case ATOMISP_IOC_S_BAYER_NR:
+ return mfld_isp_bayer_nr(ci, 1,
+ (struct sh_css_isp_nr_config *)arg);
+
+ case ATOMISP_IOC_G_TNR:
+ return mfld_isp_tnr(ci, 0, (struct sh_css_isp_tnr_config *)arg);
+
+ case ATOMISP_IOC_S_TNR:
+ return mfld_isp_tnr(ci, 1, (struct sh_css_isp_tnr_config *)arg);
+
+ case ATOMISP_IOC_G_HISTOGRAM:
+ return mfld_isp_histogram(ci, 0, arg);
+
+ case ATOMISP_IOC_S_HISTOGRAM:
+ return mfld_isp_histogram(ci, 1, arg);
+
+ case ATOMISP_IOC_G_BLACK_LEVEL_COMP:
+ return mfld_isp_black_level(ci, 0,
+ (struct sh_css_isp_ob_config *)arg);
+
+ case ATOMISP_IOC_S_BLACK_LEVEL_COMP:
+ return mfld_isp_black_level(ci, 1,
+ (struct sh_css_isp_ob_config *)arg);
+
+ case ATOMISP_IOC_G_YCC_NR:
+ return mfld_isp_ycc_nr(ci, 0,
+ (struct sh_css_isp_nr_config *)arg);
+
+ case ATOMISP_IOC_S_YCC_NR:
+ return mfld_isp_ycc_nr(ci, 1,
+ (struct sh_css_isp_nr_config *)arg);
+
+ case ATOMISP_IOC_G_EE:
+ return mfld_isp_ee(ci, 0, (struct sh_css_isp_ee_config *)arg);
+
+ case ATOMISP_IOC_S_EE:
+ return mfld_isp_ee(ci, 1, (struct sh_css_isp_ee_config *)arg);
+
+ case ATOMISP_IOC_G_DIS_STAT:
+ return mfld_isp_dis_stat(ci, 0,
+ (struct mfld_isp_dis_config *)arg);
+
+ case ATOMISP_IOC_S_DIS_STAT:
+ return mfld_isp_dis_stat(ci, 1,
+ (struct mfld_isp_dis_config *)arg);
+
+ case ATOMISP_IOC_G_ISP_PARM:
+ return mfld_isp_param(ci, 0, (struct mfld_isp_parm *)arg);
+
+ case ATOMISP_IOC_S_ISP_PARM:
+ return mfld_isp_param(ci, 1, (struct mfld_isp_parm *)arg);
+
+ case ATOMISP_IOC_G_3A_STAT:
+ return mfld_isp_3a_stat(ci, 0, (struct mfld_3a_stat *)arg);
+
+ case ATOMISP_IOC_G_ISP_GAMMA:
+ return mfld_isp_get_gamma(ci, 0,
+ (struct mfld_isp_gamma_tbl *)arg);
+
+ case ATOMISP_IOC_S_ISP_GAMMA:
+ return mfld_isp_set_gamma(ci, 0,
+ (struct mfld_isp_gamma_tbl *)arg);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static void mfld_isp_init_struct(struct ci_device *ci)
+{
+ if (ci == NULL)
+ return;
+
+ ci->width = ci->height = 0;
+ ci->framesize = ci->imagesize = 0;
+ ci->pixeldepth = 0;
+ ci->pixelformat = 0;
+ ci->imagebuf = NULL;
+ ci->bufnum = 0;
+ ci->sh_pixelformat = -1;
+ ci->streaming = 0;
+ ci->buf_allocated = 0;
+ ci->run_mode = CI_MODE_STILL_CAPTURE;
+ ci->color_effect = V4L2_COLORFX_NONE;
+ ci->bad_pixel_en = 1;
+ ci->gdc_cac_en = 0;
+ ci->video_dis_en = 0;
+ ci->sc_en = 0;
+ ci->fpn_en = 0;
+ ci->xnr_en = 0;
+ ci->false_color = 0;
+ ci->online_process = 1; /* By default we turn on online process */
+ ci->bayer_downscaling = 0; /* By default we turn on online process */
+
+ /* Add for channel */
+ if (ci->cameras[0].camera)
+ ci->camera_curr = 0;
+
+ /* TNR configure init */
+ sh_css_params_get_default_tnr_config
+ ((const struct sh_css_isp_tnr_config **)(&ci->tnr_config));
+ /* NR configure init */
+ sh_css_params_get_default_nr_config
+ ((const struct sh_css_isp_nr_config **)(&ci->nr_config));
+ /* EE configure init */
+ sh_css_params_get_default_ee_config
+ ((const struct sh_css_isp_ee_config **)(&ci->ee_config));
+ /* OB configure init */
+ sh_css_params_get_default_ob_config
+ ((const struct sh_css_isp_ob_config **)(&ci->ob_config));
+}
+
+#ifdef USE_DYNAMIC_BIN
+char *_hrt_blob_sp;
+char *_hrt_blob_isp_bayer_ds_var;
+char *_hrt_blob_isp_copy_var;
+char *_hrt_blob_isp_primary_16mp;
+char *_hrt_blob_isp_primary_14mp;
+char *_hrt_blob_isp_primary_var;
+char *_hrt_blob_isp_primary_ds;
+char *_hrt_blob_isp_primary_small;
+char *_hrt_blob_isp_preview_var;
+char *_hrt_blob_isp_preview_ds;
+char *_hrt_blob_isp_video_online;
+char *_hrt_blob_isp_video_online_nodz;
+char *_hrt_blob_isp_video_online_ds;
+char *_hrt_blob_isp_video_offline;
+char *_hrt_blob_isp_xnr_var;
+char *_hrt_blob_isp_pregdc_var;
+char *_hrt_blob_isp_gdc_var;
+char *_hrt_blob_isp_postgdc_var;
+char *_hrt_blob_isp_vf_pp;
+
+unsigned int _hrt_text_size_of_sp;
+unsigned int _hrt_size_of_sp;
+
+unsigned int _hrt_text_size_of_isp_bayer_ds_var;
+unsigned int _hrt_size_of_isp_bayer_ds_var;
+
+unsigned int _hrt_text_size_of_isp_copy_var;
+unsigned int _hrt_size_of_isp_copy_var;
+
+unsigned int _hrt_text_size_of_isp_gdc_var;
+unsigned int _hrt_size_of_isp_gdc_var;
+
+unsigned int _hrt_text_size_of_isp_postgdc_var;
+unsigned int _hrt_size_of_isp_postgdc_var;
+
+unsigned int _hrt_text_size_of_isp_pregdc_var;
+unsigned int _hrt_size_of_isp_pregdc_var;
+
+unsigned int _hrt_text_size_of_isp_preview_ds;
+unsigned int _hrt_size_of_isp_preview_ds;
+
+unsigned int _hrt_text_size_of_isp_preview_var;
+unsigned int _hrt_size_of_isp_preview_var;
+
+unsigned int _hrt_text_size_of_isp_primary_14mp;
+unsigned int _hrt_size_of_isp_primary_14mp;
+
+unsigned int _hrt_text_size_of_isp_primary_16mp;
+unsigned int _hrt_size_of_isp_primary_16mp;
+
+unsigned int _hrt_text_size_of_isp_primary_ds;
+unsigned int _hrt_size_of_isp_primary_ds;
+
+unsigned int _hrt_text_size_of_isp_primary_small;
+unsigned int _hrt_size_of_isp_primary_small;
+
+unsigned int _hrt_text_size_of_isp_primary_var;
+unsigned int _hrt_size_of_isp_primary_var;
+
+unsigned int _hrt_text_size_of_isp_vf_pp;
+unsigned int _hrt_size_of_isp_vf_pp;
+
+unsigned int _hrt_text_size_of_isp_video_offline;
+unsigned int _hrt_size_of_isp_video_offline;
+
+unsigned int _hrt_text_size_of_isp_video_online_ds;
+unsigned int _hrt_size_of_isp_video_online_ds;
+
+unsigned int _hrt_text_size_of_isp_video_online_nodz;
+unsigned int _hrt_size_of_isp_video_online_nodz;
+
+unsigned int _hrt_text_size_of_isp_video_online;
+unsigned int _hrt_size_of_isp_video_online;
+
+unsigned int _hrt_text_size_of_isp_xnr_var;
+unsigned int _hrt_size_of_isp_xnr_var;
+
+const struct firmware *isp_fw_loaded;
+struct bi_h *isp_fw[SUPPORTED_BIN];
+
+/*
+ * Setup the blob firmware to the loaded firmware
+ * replace the file such as isp_copy_5mp.blob.h
+ * Fixme: use micro to reduce the code lines
+ */
+
+/*Load the Binary Header*/
+static void mfld_isp_get_binary_header(const struct firmware *ci_fw)
+{
+ struct bi_h *bi;
+ struct bi_file_h bf;
+ int i, binary_nr = 0;
+
+ /*bf = (struct bi_file_h *)(ci_fw->data);*/
+ memcpy(&bf, ci_fw->data, sizeof(struct bi_file_h));
+ mfld_isp_dbg(KERN_INFO, "isp fw version %d\n", bf.version);
+ binary_nr = bf.binary_nr;
+ mfld_isp_dbg(KERN_DEBUG, "Binary find %d\n", binary_nr);
+ for (i = 0; i < binary_nr + 1; i++) {
+ bi = (struct bi_h *)(ci_fw->data + sizeof(struct bi_file_h) +
+ sizeof(struct bi_h) *i);
+ mfld_isp_dbg(KERN_DEBUG, "Collect binary %d\n", i);
+ if ((bi->ID) >= 0) {
+ mfld_isp_dbg(KERN_DEBUG, "Collect correct binary %d,"
+ "binary %d\n", i, bi->ID);
+ mfld_isp_dbg(KERN_DEBUG, "Size %x, offset %x\n",
+ bi->size, bi->offset);
+ isp_fw[bi->ID] = bi;
+ }
+ }
+}
+
+static void mfld_isp_setup_fw_size(void)
+{
+ /* This is for SP binary */
+ _hrt_text_size_of_sp = isp_fw[isp_bin_sp]->text_size;
+ _hrt_size_of_sp = isp_fw[isp_bin_sp]->size;
+
+ /* This is for ISP binary */
+ _hrt_text_size_of_isp_bayer_ds_var =
+ isp_fw[isp_bin_bayer_ds_var]->text_size;
+ _hrt_size_of_isp_bayer_ds_var = isp_fw[isp_bin_bayer_ds_var]->size;
+ _hrt_text_size_of_isp_copy_var = isp_fw[isp_bin_copy_var]->text_size;
+ _hrt_size_of_isp_copy_var = isp_fw[isp_bin_copy_var]->size;
+ _hrt_text_size_of_isp_gdc_var = isp_fw[isp_bin_gdc_var]->text_size;
+ _hrt_size_of_isp_gdc_var = isp_fw[isp_bin_gdc_var]->size;
+ _hrt_text_size_of_isp_postgdc_var =
+ isp_fw[isp_bin_postgdc_var]->text_size;
+ _hrt_size_of_isp_postgdc_var = isp_fw[isp_bin_postgdc_var]->size;
+ _hrt_text_size_of_isp_pregdc_var =
+ isp_fw[isp_bin_pregdc_var]->text_size;
+ _hrt_size_of_isp_pregdc_var = isp_fw[isp_bin_pregdc_var]->size;
+ _hrt_text_size_of_isp_preview_ds =
+ isp_fw[isp_bin_preview_ds]->text_size;
+ _hrt_size_of_isp_preview_ds = isp_fw[isp_bin_preview_ds]->size;
+ _hrt_text_size_of_isp_preview_var =
+ isp_fw[isp_bin_preview_var]->text_size;
+ _hrt_size_of_isp_preview_var = isp_fw[isp_bin_preview_var]->size;
+ _hrt_text_size_of_isp_primary_14mp =
+ isp_fw[isp_bin_primary_14mp]->text_size;
+ _hrt_size_of_isp_primary_14mp = isp_fw[isp_bin_primary_14mp]->size;
+ _hrt_text_size_of_isp_primary_16mp =
+ isp_fw[isp_bin_primary_16mp]->text_size;
+ _hrt_size_of_isp_primary_16mp = isp_fw[isp_bin_primary_16mp]->size;
+ _hrt_text_size_of_isp_primary_ds =
+ isp_fw[isp_bin_primary_ds]->text_size;
+ _hrt_size_of_isp_primary_ds = isp_fw[isp_bin_primary_ds]->size;
+ _hrt_text_size_of_isp_primary_small =
+ isp_fw[isp_bin_primary_small]->text_size;
+ _hrt_size_of_isp_primary_small = isp_fw[isp_bin_primary_small]->size;
+ _hrt_text_size_of_isp_primary_var =
+ isp_fw[isp_bin_primary_var]->text_size;
+ _hrt_size_of_isp_primary_var = isp_fw[isp_bin_primary_var]->size;
+ _hrt_text_size_of_isp_vf_pp = isp_fw[isp_bin_vf_pp]->text_size;
+ _hrt_size_of_isp_vf_pp = isp_fw[isp_bin_vf_pp]->size;
+ _hrt_text_size_of_isp_video_offline =
+ isp_fw[isp_bin_video_offline]->text_size;
+ _hrt_size_of_isp_video_offline = isp_fw[isp_bin_video_offline]->size;
+ _hrt_text_size_of_isp_video_online_ds =
+ isp_fw[isp_bin_video_online_ds]->text_size;
+ _hrt_size_of_isp_video_online_ds =
+ isp_fw[isp_bin_video_online_ds]->size;
+ _hrt_text_size_of_isp_video_online_nodz =
+ isp_fw[isp_bin_video_online_nodz]->text_size;
+ _hrt_size_of_isp_video_online_nodz =
+ isp_fw[isp_bin_video_online_nodz]->size;
+ _hrt_text_size_of_isp_video_online =
+ isp_fw[isp_bin_video_online]->text_size;
+ _hrt_size_of_isp_video_online = isp_fw[isp_bin_video_online]->size;
+ _hrt_text_size_of_isp_xnr_var = isp_fw[isp_bin_xnr_var]->text_size;
+ _hrt_size_of_isp_xnr_var = isp_fw[isp_bin_xnr_var]->size;
+}
+
+static void mfld_isp_setup_fw(const struct firmware *ci_fw)
+{
+ _hrt_blob_sp = (char *)
+ (isp_fw[isp_bin_sp]->offset + ci_fw->data);
+
+ _hrt_blob_isp_copy_var = (char *)
+ (isp_fw[isp_bin_copy_var]->offset + ci_fw->data);
+
+ _hrt_blob_isp_bayer_ds_var = (char *)
+ (isp_fw[isp_bin_bayer_ds_var]->offset + ci_fw->data);
+
+ _hrt_blob_isp_primary_16mp = (char *)
+ (isp_fw[isp_bin_primary_16mp]->offset + ci_fw->data);
+
+ _hrt_blob_isp_primary_14mp = (char *)
+ (isp_fw[isp_bin_primary_14mp]->offset + ci_fw->data);
+
+ _hrt_blob_isp_primary_var = (char *)
+ (isp_fw[isp_bin_primary_var]->offset + ci_fw->data);
+
+ _hrt_blob_isp_primary_ds = (char *)
+ (isp_fw[isp_bin_primary_ds]->offset + ci_fw->data);
+
+ _hrt_blob_isp_primary_small = (char *)
+ (isp_fw[isp_bin_primary_small]->offset + ci_fw->data);
+
+ _hrt_blob_isp_preview_var = (char *)
+ (isp_fw[isp_bin_preview_var]->offset + ci_fw->data);
+
+ _hrt_blob_isp_preview_ds = (char *)
+ (isp_fw[isp_bin_preview_ds]->offset + ci_fw->data);
+
+ _hrt_blob_isp_video_online = (char *)
+ (isp_fw[isp_bin_video_online]->offset + ci_fw->data);
+
+ _hrt_blob_isp_video_online_ds = (char *)
+ (isp_fw[isp_bin_video_online_ds]->offset + ci_fw->data);
+
+ _hrt_blob_isp_video_online_nodz = (char *)
+ (isp_fw[isp_bin_video_online_nodz]->offset + ci_fw->data);
+
+ _hrt_blob_isp_video_offline = (char *)
+ (isp_fw[isp_bin_video_offline]->offset + ci_fw->data);
+
+ _hrt_blob_isp_pregdc_var = (char *)
+ (isp_fw[isp_bin_pregdc_var]->offset + ci_fw->data);
+
+ _hrt_blob_isp_gdc_var = (char *)
+ (isp_fw[isp_bin_gdc_var]->offset + ci_fw->data);
+
+ _hrt_blob_isp_postgdc_var = (char *)
+ (isp_fw[isp_bin_postgdc_var]->offset + ci_fw->data);
+
+ _hrt_blob_isp_xnr_var = (char *)
+ (isp_fw[isp_bin_xnr_var]->offset + ci_fw->data);
+
+ _hrt_blob_isp_vf_pp = (char *)
+ (isp_fw[isp_bin_vf_pp]->offset + ci_fw->data);
+
+ mfld_isp_setup_fw_size();
+}
+
+/*
+ * Load the firmware from the User with the udev help
+ * Todo: Do we need to save the loaded firmware to some where else?
+ */
+/*static struct platform_device *ci_pdev;*/
+static int mfld_isp_load_all_firmwares(struct device *dev)
+{
+ int rc = 0;
+ mfld_isp_dbg(KERN_INFO, "loading isp firmware ...\n");
+
+ rc = request_firmware(&isp_fw_loaded, FW_PATH, dev);
+ if (rc < 0) {
+ if (rc == -ENOENT)
+ mfld_isp_dbg(KERN_INFO,
+ "atomisp: Error firmware %s not found.\n", FW_PATH);
+ else
+ mfld_isp_dbg(KERN_INFO,
+ "atomisp: Error %d while requesting firmware %s\n",
+ rc, FW_PATH);
+ /*platform_device_unregister(ci_pdev);*/
+ return rc;
+ }
+ mfld_isp_dbg(KERN_DEBUG,
+ "isp_fw_file info: file:%p, size:%x\n",
+ isp_fw_loaded->data,
+ isp_fw_loaded->size);
+ mfld_isp_get_binary_header(isp_fw_loaded);
+ mfld_isp_setup_fw(isp_fw_loaded);
+ /*mfld_isp_setup_parm(isp_fw_loaded);*/
+ mfld_isp_dbg(KERN_INFO, "loading isp firmware ... done\n");
+ return rc;
+}
+
+static void mfld_isp_release_firmware(void)
+{
+ if (isp_fw_loaded != NULL) {
+ release_firmware(isp_fw_loaded);
+ isp_fw_loaded = NULL;
+ }
+}
+#endif
+
+static void *kernel_malloc(size_t bytes)
+{
+ return kmalloc(bytes, GFP_KERNEL);
+}
+
+/* kfree is declared with const void * argument even though it's
+ clearly not const. We work around this here. */
+static void kernel_free(void *ptr)
+{
+ kfree(ptr);
+}
+
+int myprintk(const char *fmt, ...)
+{
+ va_list args;
+ int printed;
+
+ va_start(args, fmt);
+ printed = vprintk(fmt, args);
+ va_end(args);
+
+ return printed;
+}
+
+/*
+ * file operation functions
+ */
+static int mfld_isp_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ int ret;
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_open\n");
+ if (isp_probe == 0)
+ return -1;
+
+ if (ci->open) {
+ mfld_isp_dbg(KERN_ERR, "Can only open once now\n");
+ return -EBUSY;
+ }
+
+ /* runtime power management, turn on ISP */
+ ret = pm_runtime_get_sync(vdev->v4l2_dev->dev);
+ if (ret < 0) {
+ mfld_isp_dbg(KERN_ERR, "Failed to power on device\n");
+ return -EINVAL;
+ }
+
+ ci->open++;
+
+ mfld_isp_init_struct(ci);
+
+#ifdef USE_DYNAMIC_BIN
+ /* Load firmware from user space */
+ ret = v4l2_subdev_call(ci->cameras[ci->camera_curr].camera,
+ core, init, 1);
+
+ if (ret == -1 || ret == -EINVAL) {
+ mfld_isp_dbg(KERN_ERR, "sensor firmware failed\n");
+ return ret;
+ }
+
+ if (mfld_isp_load_all_firmwares(&vdev->dev) < 0) {
+ mfld_isp_dbg(KERN_ERR, "Load firmwares failed\n");
+ ci->open--;
+ pm_runtime_put(vdev->v4l2_dev->dev);
+ return -1;
+ }
+#endif
+ /* Init ISP */
+ return_on_css_error(sh_css_init
+ (kernel_malloc, kernel_free,
+ sh_css_interrupt_setting_disabled));
+ return_on_css_error(sh_css_set_print_function(myprintk));
+
+ return_on_css_error(sh_css_params_allocate(&ci->isp_params));
+ /* now set the default parameters. */
+ return_on_css_error(sh_css_params_default(ci->isp_params));
+
+ mfld_isp_dbg(KERN_DEBUG, "open done\n");
+
+ return 0;
+}
+
+static int mfld_isp_close(struct ci_device *ci)
+{
+ int i;
+ int ret;
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_close\n");
+
+ if (ci == NULL)
+ return -EBADF;
+
+ if (ci->open <= 0) {
+ mfld_isp_dbg(KERN_ALERT, "device already closed\n");
+ return -EBADF;
+ }
+ /* in case image buf is not freed */
+ if (ci->buf_allocated) {
+ for (i = 0; i < ci->bufnum; i++)
+ free_buffer(ci->imagebuf[i]);
+ kfree(ci->imagebuf);
+ ci->imagebuf = NULL;
+ if (ci->vf_frame)
+ sh_css_frame_free(ci->vf_frame);
+ ci->vf_frame = NULL;
+ ci->buf_allocated = 0;
+ }
+#ifdef USE_DYNAMIC_BIN
+ mfld_isp_release_firmware();
+#endif
+
+ ret = v4l2_subdev_call(ci->cameras[ci->camera_curr].camera,
+ core, init, 0);
+
+ if (ret == -1 || ret == -EINVAL) {
+ mfld_isp_dbg(KERN_ERR, "sensor firmware failed\n");
+ return ret;
+ }
+
+ ci->open--;
+
+ sh_css_uninit();
+
+ /* uninit ISP parameter */
+ sh_css_params_free(ci->isp_params);
+ return 0;
+}
+
+static int mfld_isp_release(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+ int ret;
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_release\n");
+
+ ret = mfld_isp_close(ci);
+ if (!ret)
+ pm_runtime_put(vdev->v4l2_dev->dev);
+
+ return ret;
+}
+
+static int __do_isp_mm_remap(struct vm_area_struct *vma,
+ void *isp_virt, __u32 host_virt, __u32 pgnr)
+{
+ __u32 pfn;
+
+ while (pgnr) {
+ pfn = hmm_virt_to_phys(isp_virt) >> PAGE_SHIFT;
+ if (remap_pfn_range(vma, host_virt, pfn,
+ PAGE_SIZE, PAGE_SHARED)) {
+ mfld_isp_dbg(KERN_ERR, "remap_pfn_range err.\n");
+ return -1;
+ }
+
+ isp_virt += PAGE_SIZE;
+ host_virt += PAGE_SIZE;
+ pgnr--;
+ }
+
+ return 0;
+}
+
+static int frame_mmap(const struct sh_css_frame *frame,
+ struct vm_area_struct *vma)
+{
+ void *isp_virt;
+ __u32 host_virt;
+ __u32 pgnr;
+
+ if (!frame) {
+ mfld_isp_dbg(KERN_ERR, "NULL frame pointer.\n");
+ return -EINVAL;
+ }
+
+ host_virt = vma->vm_start;
+ isp_virt = frame->data;
+ get_frame_pgnr(frame, &pgnr);
+
+ if (__do_isp_mm_remap(vma, isp_virt, host_virt, pgnr))
+ return -1;
+
+ return 0;
+}
+
+static int __mmap_image_frame(struct vm_area_struct *vma, struct ci_buffer *buf,
+ __u32 vm_flags)
+{
+ __u32 pgnr;
+ __u32 start, end;
+ __u32 size;
+
+ start = vma->vm_start;
+ end = vma->vm_end;
+ size = buf->size;
+
+ if (PAGE_ALIGN(size) != (end - start)) {
+ mfld_isp_dbg(KERN_ERR, "vma size is not equal to memory size: "
+ "vma_size = 0x%x, mem_size = 0x%x\n",
+ (end - start), PAGE_ALIGN(size));
+ return -1;
+ }
+
+ pgnr = PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+ if (frame_mmap(buf->handle, vma)) {
+ mfld_isp_dbg(KERN_ERR, "frame_mmap failed.\n");
+ return -1;
+ }
+ vma->vm_flags |= vm_flags;
+
+ return 0;
+}
+
+static int mfld_isp_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+
+ __u32 start = vma->vm_start;
+ __u32 end = vma->vm_end;
+ __u32 offset = vma->vm_pgoff << PAGE_SHIFT;
+ __u32 size = end - start;
+ struct sh_css_frame *raw_virt_addr;
+ int buf_idx;
+
+ mfld_isp_dbg(KERN_DEBUG, "mfld_isp_mmap\n");
+
+ if (!(vma->vm_flags & (VM_WRITE | VM_READ)))
+ return -EACCES;
+
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ /*
+ * mmap for ISP parameter structure
+ */
+ if (vma->vm_pgoff == (ISP_PARAM_MMAP_OFFSET >> PAGE_SHIFT)) {
+ if (ci->online_process != 0)
+ return -EINVAL;
+
+ raw_virt_addr = sh_css_get_raw_frame();
+ if (raw_virt_addr == NULL) {
+ mfld_isp_dbg(KERN_ERR, "Failed to request RAW frame\n");
+ return -EINVAL;
+ }
+
+ mfld_isp_dbg(KERN_DEBUG, "raw = %x, size = %d, ALIGN = %d\n",
+ (unsigned int)raw_virt_addr, size,
+ PAGE_ALIGN(raw_virt_addr->data_bytes));
+ if (size != PAGE_ALIGN(raw_virt_addr->data_bytes)) {
+ mfld_isp_dbg(KERN_ERR, "incorrect size for mmap ISP"
+ " Raw Frame\n");
+ return -EINVAL;
+ }
+
+ /*ci->online_process = 0;*/
+ /*return_on_css_error(sh_css_capture_enable_online*/
+ /*(ci->online_process));*/
+ if (frame_mmap(raw_virt_addr, vma)) {
+ mfld_isp_dbg(KERN_ERR, "frame_mmap failed.\n");
+ return -1;
+ }
+ vma->vm_flags |= VM_RESERVED;
+ return 0;
+ }
+
+ /*
+ * mmap for NORMAL frames
+ */
+ if (offset >= ci->bufnum * ci->imagesize) {
+ mfld_isp_dbg(KERN_ERR, "offset extends max buffer size:"
+ " bufsize = %d, offset = %d\n",
+ ci->bufnum * ci->imagesize, offset);
+ return -EINVAL;
+ }
+
+ if (size != ci->imagesize) {
+ mfld_isp_dbg(KERN_ERR, "user space virtual address space range"
+ " for mmap is not the same as frame buffer size:"
+ " %d, %d", size, ci->imagesize);
+ return -EINVAL;
+ }
+
+ if (ci->imagebuf == NULL) {
+ mfld_isp_dbg(KERN_ERR, "buffer not allocated\n");
+ return -EINVAL;
+ }
+
+ buf_idx = offset / ci->imagesize;
+
+ mfld_isp_dbg(KERN_DEBUG, "try to mmap buffer: %d\n", buf_idx);
+
+ return __mmap_image_frame(vma, ci->imagebuf[buf_idx], VM_RESERVED);
+}
+
+static unsigned int mfld_isp_poll(struct file *file,
+ struct poll_table_struct *pt)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct ci_device *ci = video_get_drvdata(vdev);
+
+ if (ci->streaming != 1)
+ return POLLERR;
+
+ /* Without videobuf enabled, we just return */
+ return POLLIN | POLLRDNORM;
+}
+
+static const struct v4l2_file_operations mfld_isp_fops = {
+ .owner = THIS_MODULE,
+ .open = mfld_isp_open,
+ .release = mfld_isp_release,
+ .mmap = mfld_isp_mmap,
+ .ioctl = video_ioctl2,
+ .poll = mfld_isp_poll,
+};
+
+static const struct v4l2_ioctl_ops mfld_isp_ioctl_ops = {
+ .vidioc_querycap = mfld_isp_querycap,
+ .vidioc_enum_input = mfld_isp_enum_input,
+ .vidioc_g_input = mfld_isp_g_input,
+ .vidioc_s_input = mfld_isp_s_input,
+ .vidioc_queryctrl = mfld_isp_queryctl,
+ .vidioc_s_ctrl = mfld_isp_s_ctrl,
+ .vidioc_g_ctrl = mfld_isp_g_ctrl,
+ .vidioc_s_ext_ctrls = mfld_isp_s_ext_ctrls,
+ .vidioc_g_ext_ctrls = mfld_isp_g_ext_ctrls,
+ .vidioc_enum_fmt_vid_cap = mfld_isp_enum_fmt_cap,
+ .vidioc_try_fmt_vid_cap = mfld_isp_try_fmt_cap,
+ .vidioc_g_fmt_vid_cap = mfld_isp_g_fmt_cap,
+ .vidioc_s_fmt_vid_cap = mfld_isp_s_fmt_cap,
+ .vidioc_s_fmt_type_private = mfld_isp_s_fmt_cap,
+ .vidioc_reqbufs = mfld_isp_reqbufs,
+ .vidioc_querybuf = mfld_isp_querybuf,
+ .vidioc_qbuf = mfld_isp_qbuf,
+ .vidioc_dqbuf = mfld_isp_dqbuf,
+ .vidioc_streamon = mfld_isp_streamon,
+ .vidioc_streamoff = mfld_isp_streamoff,
+ .vidioc_default = mfld_isp_vidioc_default,
+ .vidioc_cropcap = mfld_isp_cropcap,
+ .vidioc_enum_framesizes = mfld_isp_enum_framesizes,
+ .vidioc_enum_frameintervals = mfld_isp_enum_frameintervals,
+ .vidioc_s_parm = mfld_isp_s_parm,
+ .vidioc_g_parm = mfld_isp_g_parm,
+ .vidioc_g_std = mfld_isp_g_std,
+ .vidioc_s_std = mfld_isp_s_std,
+ .vidioc_g_crop = mfld_isp_g_crop,
+ .vidioc_s_crop = mfld_isp_s_crop,
+};
+
+static const struct video_device mfld_isp_video_dev = {
+ .name = "mfld_ci",
+ .minor = -1,
+ .fops = &mfld_isp_fops,
+ .release = video_device_release,
+ .ioctl_ops = &mfld_isp_ioctl_ops
+};
+
+#ifdef CONFIG_PM
+static int ospm_power_island_down(struct ci_device *);
+static int ospm_power_island_up(struct ci_device *);
+
+static int mfld_isp_runtime_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct ci_device *ci = (struct ci_device *)pci_get_drvdata(pdev);
+ int ret;
+
+ mfld_isp_dbg(KERN_DEBUG, "Get into runtime suspend function\n");
+
+ ret = pci_save_state(pdev);
+ if (ret) {
+ mfld_isp_dbg(KERN_ERR, "pci_save_state failed %d\n", ret);
+ return ret;
+ }
+
+ pci_disable_device(pdev);
+ ret += pci_set_power_state(pdev, PCI_D3hot);
+ if (ret) {
+ mfld_isp_dbg(KERN_ERR, "fail to set power state\n");
+ return ret;
+ }
+
+ ospm_power_island_down(ci);
+
+ mfld_isp_dbg(KERN_DEBUG, "Leave runtime suspend function\n");
+ return 0;
+}
+
+static int mfld_isp_runtime_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct ci_device *ci = (struct ci_device *)pci_get_drvdata(pdev);
+ int ret;
+
+ mfld_isp_dbg(KERN_DEBUG, "Get into runtime resume function\n");
+
+ pci_set_power_state(pdev, PCI_D0);
+ ospm_power_island_up(ci);
+ pci_restore_state(pdev);
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ mfld_isp_dbg(KERN_ERR, "fail to enable device in resume\n");
+ return ret;
+ }
+
+ mfld_isp_dbg(KERN_DEBUG, "Leave runtime resume function\n");
+ return 0;
+}
+
+static int mfld_isp_pci_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ struct ci_device *ci = (struct ci_device *)pci_get_drvdata(dev);
+ int ret;
+
+ mfld_isp_dbg(KERN_DEBUG, "Get into suspend function\n");
+
+#if (!defined(IMAGE_FROM_TPG))
+ ret = v4l2_subdev_call(ci->cameras[ci->camera_curr].camera, core,
+ s_power, 0);
+ if (ret) {
+ mfld_isp_dbg(KERN_ERR, "Fail to suspend sensor\n");
+ return ret;
+ }
+#endif
+
+ ret = pci_save_state(dev);
+ if (ret) {
+ mfld_isp_dbg(KERN_ERR, "pci_save_state failed %d\n", ret);
+ return ret;
+ }
+
+ pci_disable_device(dev);
+ ret += pci_set_power_state(dev, pci_choose_state(dev, state));
+ if (ret) {
+ mfld_isp_dbg(KERN_ERR, "fail to set power state\n");
+ return ret;
+ }
+
+ ospm_power_island_down(ci);
+
+ mfld_isp_dbg(KERN_DEBUG, "Leave suspend function\n");
+ return 0;
+}
+
+static int mfld_isp_pci_resume(struct pci_dev *dev)
+{
+ struct ci_device *ci = (struct ci_device *)pci_get_drvdata(dev);
+ int ret;
+
+ mfld_isp_dbg(KERN_DEBUG, "Get into resume function\n");
+
+ pci_set_power_state(dev, PCI_D0);
+ ospm_power_island_up(ci);
+ pci_restore_state(dev);
+
+ ret = pci_enable_device(dev);
+ if (ret) {
+ mfld_isp_dbg(KERN_ERR, "fail to enable device in resume\n");
+ return ret;
+ }
+#if (!defined(IMAGE_FROM_TPG))
+ ret = v4l2_subdev_call(ci->cameras[ci->camera_curr].camera, core,
+ s_power, 1);
+ if (ret) {
+ mfld_isp_dbg(KERN_ERR, "Fail to resume sensor\n");
+ return ret;
+ }
+#endif
+
+ mfld_isp_dbg(KERN_DEBUG, "Leave resume function\n");
+ return 0;
+}
+#endif
+
+#ifdef PNW_B0
+static void set_alt_fn_for_i2c4_5(void)
+{
+ void __iomem *gpio1_base;
+ u32 gafr4_l;
+
+ gpio1_base = ioremap_nocache(0xff12c800, 0x74);
+ if (!gpio1_base)
+ mfld_isp_dbg(KERN_DEBUG, "gpio1_base mapped failed\n");
+
+ mfld_isp_dbg(KERN_DEBUG, "try to set alt fn for i2c4\n");
+
+ /* GPIO O/P Enable */
+ writel(0xffe80303, gpio1_base + 0x10);
+ mfld_isp_dbg(KERN_DEBUG, "(0xffe80303)0x%x\n",
+ readl(gpio1_base + 0x10));
+ gafr4_l = readl(gpio1_base + 0x5c);
+ mfld_isp_dbg(KERN_DEBUG, "orig vale- 0x%x", gafr4_l);
+ writel((gafr4_l | 0x00055000), gpio1_base + 0x5c);
+
+ gafr4_l = readl(gpio1_base + 0x5c);
+ mfld_isp_dbg(KERN_DEBUG, "change val - 0x%x", gafr4_l);
+
+ mfld_isp_dbg(KERN_DEBUG, "done set alt fn for i2c4\n");
+
+}
+
+/*
+ * port: 0 is 4 Lane port and 1 is 1 Lane port
+ * flag: 0 is off and 1 is on
+ */
+static int mfld_isp_camera_flis_clock(int port, int flag)
+{
+ u32 *ipc_wbuf;
+ u8 cbuf[16] = { '\0' };
+ int ipc_ret = 0;
+
+ ipc_wbuf = (u32 *)&cbuf;
+ cbuf[0] = port; /* 0 - 14MP camera, 1 - 2MP camera */
+ cbuf[1] = flag; /* 0 - off, 1 - on */
+ /* is this correct for sub type */
+ ipc_ret = intel_scu_ipc_command(0xE7, 0,
+ ipc_wbuf, 2, NULL, 0);
+
+ if (ipc_ret != 0)
+ mfld_isp_dbg(KERN_CRIT, "Error Setting Camera FLIS Clock %x\n",
+ ipc_ret);
+
+ return ipc_ret;
+
+}
+#endif
+
+static int mfld_isp_subdev_probe(struct ci_device *ci_dev)
+{
+ struct v4l2_subdev *subdev = NULL;
+ struct v4l2_subdev *motor_sd = NULL;
+ struct i2c_adapter *adapter = NULL;
+ char *name;
+ u8 addr;
+ int i2c_id;
+ int i;
+ int j = 0;
+
+ /* This Code is for Penwell B0 ES2 board only */
+ /* turn on vprog2 and vpro1 power */
+ __u16 ipc_addr = 0xd6;
+ __u8 ipc_data = 0xff;
+ intel_scu_ipc_iowrite8(ipc_addr, ipc_data);
+ mfld_isp_dbg(KERN_DEBUG, "turn on vprog2 power\n");
+
+ ipc_addr = 0xd7;
+ ipc_data = 0xff;
+ intel_scu_ipc_iowrite8(ipc_addr, ipc_data);
+ mfld_isp_dbg(KERN_DEBUG, "turn on vprog1 power\n");
+
+ /* turn on camera flis registers */
+ mfld_isp_camera_flis_clock(0, 1); /* primary camera */
+ mfld_isp_camera_flis_clock(1, 1); /* secondary camera */
+ mfld_isp_dbg(KERN_INFO, "turn on camera clock flis\n");
+ set_alt_fn_for_i2c4_5();
+
+ /* NOTE: Add some GPIO control here */
+ /* Add power control here for sensor */
+ /* FIXME: Need to double confirm with Prajnesh */
+
+ for (i = 0; i < N_SUBDEV; i++) {
+ switch (mfld_isp_subdev_table[i].subdev_type) {
+ case CAMERA_SENSOR:
+ /*handle camera sensor first */
+ name = mfld_isp_subdev_table[i].camera.name;
+ addr = mfld_isp_subdev_table[i].camera.i2c_addr;
+ i2c_id = mfld_isp_subdev_table[i].camera.i2c_id;
+
+ adapter = i2c_get_adapter(i2c_id);
+ if (adapter == NULL) {
+ mfld_isp_dbg(KERN_ERR,
+ "Failed to find i2c adapter for"
+ " subdev %s\n", name);
+ break;
+ }
+ mfld_isp_dbg(KERN_INFO,
+ "Found adapter %s for subdev %s\n",
+ adapter->name, name);
+
+ subdev = v4l2_i2c_new_subdev(&ci_dev->v4l2_dev, adapter,
+ name, name, addr, NULL);
+ if (subdev == NULL) {
+ mfld_isp_dbg(KERN_WARNING, "Camera %s not"
+ " found\n", name);
+ break;
+ }
+
+ for (j = 0; j < N_SUBDEV; j++)
+ if (!ci_dev->cameras[j].camera) {
+ ci_dev->cameras[j].camera = subdev;
+ ci_dev->cameras[j].type = CAMERA_SENSOR;
+ ci_dev->camera_curr = j;
+ break;
+ }
+ if (j >= N_SUBDEV) {
+ mfld_isp_dbg(KERN_WARNING, "Already found %d "
+ "cameras\n", 4);
+ break;
+ }
+ mfld_isp_dbg(KERN_INFO,
+ "Subdev %s successfully register\n", name);
+ break;
+
+ case CAMERA_SENSOR_MOTOR:
+ /*handle camera motor then */
+ name = mfld_isp_subdev_table[i].motor.name;
+ addr = mfld_isp_subdev_table[i].motor.i2c_addr;
+ i2c_id = mfld_isp_subdev_table[i].motor.i2c_id;
+
+ adapter = i2c_get_adapter(i2c_id);
+ if (adapter == NULL) {
+ mfld_isp_dbg(KERN_ERR,
+ "Failed to find i2c "
+ "adapter for subdev %s\n",
+ name);
+ break;
+ }
+ mfld_isp_dbg(KERN_INFO, "Found adapter %s for"
+ " subdev %s\n",
+ adapter->name, name);
+
+ motor_sd =
+ v4l2_i2c_new_subdev(&ci_dev->v4l2_dev,
+ adapter, name, name,
+ addr, NULL);
+ if (motor_sd == NULL) {
+ mfld_isp_dbg(KERN_INFO,
+ "Motor %s not found\n", name);
+ break;
+ }
+
+ if (ci_dev->cameras[j].motor == NULL) {
+ ci_dev->cameras[j].motor = motor_sd;
+ ci_dev->cameras[j].type =
+ CAMERA_SENSOR_MOTOR;
+ }
+ mfld_isp_dbg(KERN_INFO,
+ "Subdev %s successfully register\n",
+ name);
+ break;
+ case LED_FLASH:
+ case XENON_FLASH:
+ name = mfld_isp_subdev_table[i].flash.name;
+ addr = mfld_isp_subdev_table[i].flash.i2c_addr;
+ i2c_id = mfld_isp_subdev_table[i].flash.i2c_id;
+
+ adapter = i2c_get_adapter(i2c_id);
+ if (adapter == NULL) {
+ mfld_isp_dbg(KERN_ERR,
+ "Failed to find i2c adapter for"
+ "subdev %s\n", name);
+ break;
+ }
+ mfld_isp_dbg(KERN_INFO, "Found adapter %s for"
+ "subdev %s\n", adapter->name, name);
+
+ subdev = v4l2_i2c_new_subdev(&ci_dev->v4l2_dev, adapter,
+ name, name, addr, NULL);
+ if (subdev == NULL) {
+ mfld_isp_dbg(KERN_WARNING,
+ "Flash %s not found\n", name);
+ break;
+ }
+
+ if (mfld_isp_subdev_table[i].subdev_type == LED_FLASH)
+ ci_dev->led_flash = subdev;
+ else
+ ci_dev->xenon_flash = subdev;
+
+ mfld_isp_dbg(KERN_INFO,
+ "Subdev %s successfully register\n", name);
+ break;
+ }
+
+ }
+
+ /*Check camera for at least one subdev in it */
+ if (!ci_dev->cameras[0].camera) {
+ printk(KERN_INFO "atomisp: "
+ "no camera attached or fail to detect\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static inline u32 MSG_READ32(uint port, uint offset)
+{
+ int mcr = (0x10 << 24) | (port << 16) | (offset << 8);
+ outl(0x800000D0, 0xCF8);
+ outl(mcr, 0xCFC);
+ outl(0x800000D4, 0xCF8);
+ return inl(0xcfc);
+}
+
+static inline void MSG_WRITE32(uint port, uint offset, u32 value)
+{
+ int mcr = (0x11 << 24) | (port << 16) | (offset << 8) | 0xF0;
+ outl(0x800000D4, 0xCF8);
+ outl(value, 0xcfc);
+ outl(0x800000D0, 0xCF8);
+ outl(mcr, 0xCFC);
+}
+
+#define OSPM_ISP_D3_MASK 0x300
+#define OSPM_CAMERA_D3_MASK 0xC00
+#define OSPM_PUNIT_APM_STS 0x4
+static int ospm_power_island_down(struct ci_device *ci_dev)
+{
+ u32 pwr_cnt = 0;
+ u32 pwr_mask = 0;
+ u32 pwr_sts = 0;
+ int count = 0;
+
+ mfld_isp_dbg(KERN_INFO, "Entry %s\n", __func__);
+
+ pwr_cnt |= OSPM_ISP_D3_MASK;
+ pwr_mask |= OSPM_ISP_D3_MASK;
+
+ pwr_cnt |= inl(ci_dev->apm_base);
+ mfld_isp_dbg(KERN_INFO, "%s, set pwr_cnt = %x\n", __func__, pwr_cnt);
+ outl(pwr_cnt, ci_dev->apm_base);
+
+ pwr_cnt = inl(ci_dev->apm_base);
+ mfld_isp_dbg(KERN_INFO, "%s, get pwr_cnt = %x\n", __func__, pwr_cnt);
+ while (true) {
+ pwr_sts = inl(ci_dev->apm_base + OSPM_PUNIT_APM_STS);
+ if ((pwr_sts & pwr_mask) == pwr_mask)
+ break;
+ else {
+ mfld_isp_dbg(KERN_INFO,
+ "Checking APM_STS register pwr_sts = %x\n",
+ pwr_sts);
+ if (count++ > 500)
+ break;
+ udelay(10);
+ }
+ }
+#ifdef ISP_CTRL_DPHY
+ /* Workaround to poweroff Iunitphy when no sensor attched */
+ pwr_cnt = MSG_READ32(0x09, 0x03);
+ pwr_cnt |= 0x300;
+ MSG_WRITE32(0x09, 0x03, pwr_cnt);
+#endif
+
+ mfld_isp_dbg(KERN_INFO, "Exit %s\n", __func__);
+ return 0;
+}
+
+static int ospm_power_island_up(struct ci_device *ci_dev)
+{
+ u32 pwr_cnt = 0;
+ u32 pwr_mask = 0;
+ u32 pwr_sts = 0;
+ int count = 0;
+
+ mfld_isp_dbg(KERN_INFO, "Entry %s\n", __func__);
+
+ pwr_cnt |= inl(ci_dev->apm_base);
+
+ pwr_cnt &= ~OSPM_ISP_D3_MASK;
+ pwr_mask |= OSPM_ISP_D3_MASK;
+
+ outl(pwr_cnt, ci_dev->apm_base);
+ while (true) {
+ pwr_sts = inl(ci_dev->apm_base + OSPM_PUNIT_APM_STS);
+ if ((pwr_sts & pwr_mask) == 0)
+ break;
+ else {
+ mfld_isp_dbg(KERN_INFO, "Checking APM_STS register\n");
+ if (count++ > 500)
+ break;
+ udelay(10);
+ }
+ }
+#ifdef ISP_CTRL_DPHY
+ /* Workaround to power-on Iunitphy when no sensor attched */
+ pwr_cnt = MSG_READ32(0x09, 0x03);
+ pwr_cnt &= ~0x300;
+ MSG_WRITE32(0x09, 0x03, pwr_cnt);
+#endif
+
+ mfld_isp_dbg(KERN_INFO, "Exit %s\n", __func__);
+ return 0;
+}
+
+static int mfld_isp_ospm_init(struct ci_device *ci_dev)
+{
+ struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
+
+ pci_write_config_dword(pci_root, 0xD0, 0x10047800);
+ pci_read_config_dword(pci_root, 0xD4, &ci_dev->ospm_base);
+ ci_dev->ospm_base &= 0xffff;
+ ci_dev->apm_reg = MSG_READ32(0x04, 0x7A);
+ ci_dev->apm_base = ci_dev->apm_reg & 0xffff;
+
+ mfld_isp_dbg(KERN_INFO, "OSPM_BASE = %x, APM_BASE = %x\n",
+ ci_dev->ospm_base, ci_dev->apm_base);
+ return 0;
+}
+
+static struct pci_driver mfld_isp_pci_driver;
+static int __devinit mfld_isp_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct ci_device *ci_dev;
+ struct video_device *vdev;
+ unsigned int start, len;
+ void __iomem *base = NULL;
+ int err;
+
+ isp_probe = 0;
+
+ ci_dev = kmalloc(sizeof(struct ci_device), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&dev->dev, "Failed to alloc CI ISP structure\n");
+ err = -ENOMEM;
+ goto kmalloc_fail1;
+ }
+ memset(ci_dev, 0, sizeof(struct ci_device));
+
+ err = v4l2_device_register(&dev->dev, &ci_dev->v4l2_dev);
+ if (err) {
+ mfld_isp_dbg(KERN_ERR, "v4l2_device_register err.\n");
+ return err;
+ }
+
+ mfld_isp_dbg(KERN_INFO, "Initialising driver...\n");
+ err = pci_enable_device(dev);
+ if (err) {
+ mfld_isp_dbg(KERN_ERR, "Failed to enable CI ISP device\n");
+ goto exit;
+ }
+
+ start = pci_resource_start(dev, 0);
+ len = pci_resource_len(dev, 0);
+
+ if (!start || len <= 0) {
+ start = 0xDF800000;
+ len = 0x400000;
+ }
+ mfld_isp_dbg(KERN_INFO, "MFLD ISP resource start 0x%x, len %d\n",
+ start, len);
+
+ err = pci_request_region(dev, 0, mfld_isp_pci_driver.name);
+ if (err) {
+ mfld_isp_dbg(KERN_ERR, "Failed to request region 0x%1x-0x%Lx\n",
+ start, (unsigned long long)pci_resource_end(dev,
+ 0));
+ goto exit;
+ }
+
+ base = ioremap_nocache(start, len);
+ if (!base) {
+ mfld_isp_dbg(KERN_ERR, "Failed to I/O memory remapping\n");
+ err = -ENOMEM;
+ goto ioremap_fail;
+ }
+ mfld_isp_dbg(KERN_INFO, "MFLD ISP base address 0x%8x\n",
+ (unsigned int)base);
+
+ pci_set_master(dev);
+
+ vdev = video_device_alloc();
+ if (!vdev) {
+ mfld_isp_dbg(KERN_ERR, "Failed to alloc video device\n");
+ err = -ENOMEM;
+ goto alloc_vdev_fail;
+ }
+ memcpy(vdev, &mfld_isp_video_dev, sizeof(struct video_device));
+ video_set_drvdata(vdev, ci_dev);
+
+ if (video_register_device(vdev, VFL_TYPE_GRABBER, -1) != 0) {
+ mfld_isp_dbg(KERN_ERR, "Failed to register video device\n");
+ err = -EINVAL;
+ goto register_fail;
+ }
+
+ snprintf(vdev->name, sizeof(vdev->name), "%s (%i)",
+ mfld_isp_video_dev.name, vdev->minor);
+
+ nr = vdev->minor;
+ mfld_isp_dbg(KERN_INFO, "Set nr to %d\n", nr);
+ ci_dev->vdev = vdev;
+ ci_dev->open = 0;
+ ci_dev->tvnorm = tvnorms;
+ ci_dev->input = 0;
+ ci_dev->base = base;
+ CI_DEV = ci_dev;
+ io_base = base;
+ VDEV = vdev;
+
+ /*init OSPM related varible */
+ mfld_isp_dbg(KERN_INFO, "Init OSPM for ISP\n");
+ mfld_isp_ospm_init(ci_dev);
+
+ pci_set_drvdata(dev, ci_dev);
+
+#if (!defined(IMAGE_FROM_TPG))
+ err = mfld_isp_subdev_probe(ci_dev);
+ if (err) {
+ mfld_isp_dbg(KERN_ERR,
+ "Failed to probe camera subdev module\n");
+ goto subdev_probe_fail;
+ }
+#endif
+
+ mfld_isp_dbg(KERN_INFO, "rumtime power management init\n");
+ pm_runtime_set_active(&dev->dev);
+ pm_runtime_enable(&dev->dev);
+ /*pm_rumtime_suspend(&dev->dev); */
+
+ mfld_isp_dbg(KERN_INFO, "Initialising atom isp driver done...\n");
+ isp_probe = 1;
+
+ return 0;
+
+#if (!defined(IMAGE_FROM_TPG))
+subdev_probe_fail:
+ pci_set_drvdata(dev, NULL);
+#endif
+
+register_fail:
+ video_device_release(vdev);
+alloc_vdev_fail:
+ kfree(ci_dev);
+kmalloc_fail1:
+ iounmap(base);
+ioremap_fail:
+ pci_release_region(dev, 0);
+exit:
+ return err;
+}
+
+static void __devexit mfld_isp_pci_remove(struct pci_dev *dev)
+{
+ struct ci_device *ci_dev = (struct ci_device *)pci_get_drvdata(dev);
+ mfld_isp_dbg(KERN_INFO, "remove driver...\n");
+
+ if (ci_dev->vdev != VDEV) {
+ mfld_isp_dbg(KERN_WARNING, "VDEV has been changed\n");
+ ci_dev->vdev = VDEV;
+ }
+
+ if (ci_dev->vdev->minor != nr) {
+ mfld_isp_dbg(KERN_WARNING, "NOTE, set the minor number back"
+ "to it's real value %d\n", nr);
+ ci_dev->vdev->minor = nr;
+ }
+ video_unregister_device(ci_dev->vdev);
+ video_device_release(ci_dev->vdev);
+ /* in case user forget to close */
+ if (ci_dev->open > 0)
+ mfld_isp_close(ci_dev);
+
+ pci_set_drvdata(dev, NULL);
+ iounmap(ci_dev->base);
+ kfree(ci_dev);
+ pci_release_region(dev, 0);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(mfld_isp_pci_tbl) = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0148)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0149)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x014A)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x014B)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x014C)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x014D)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x014E)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x014F)},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, mfld_isp_pci_tbl);
+
+static const struct dev_pm_ops mfld_isp_pm_ops = {
+ .runtime_suspend = mfld_isp_runtime_suspend,
+ .runtime_resume = mfld_isp_runtime_resume,
+};
+
+static struct pci_driver mfld_isp_pci_driver = {
+ .driver = {
+ .pm = &mfld_isp_pm_ops,
+ },
+ .name = "atomisp",
+ .id_table = mfld_isp_pci_tbl,
+ .probe = mfld_isp_pci_probe,
+ .remove = mfld_isp_pci_remove,
+#ifdef CONFIG_PM
+ .suspend = mfld_isp_pci_suspend,
+ .resume = mfld_isp_pci_resume,
+#endif
+};
+
+static int __init mfld_isp_init(void)
+{
+ mfld_isp_dbg(KERN_INFO, "Init ATOM ISP device driver,"
+ " version: %s\n", DRIVER_VERSION_STR);
+ return pci_register_driver(&mfld_isp_pci_driver);
+}
+
+static void __exit mfld_isp_exit(void)
+{
+ mfld_isp_dbg(KERN_INFO, "Exit ATOM ISP device driver\n");
+ pci_unregister_driver(&mfld_isp_pci_driver);
+}
+
+module_init(mfld_isp_init);
+module_exit(mfld_isp_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel ATOM Platform ISP Driver");
--
1.6.2.5
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0003-ISP-v4l2-driver-based-on-v4l2-API-and-framework-impl.patch
Type: application/octet-stream
Size: 146681 bytes
Desc: 0003-ISP-v4l2-driver-based-on-v4l2-API-and-framework-impl.patch
URL: <http://lists.meego.com/pipermail/meego-kernel/attachments/20101202/2b6558ec/attachment-0001.obj>
More information about the MeeGo-kernel
mailing list