From c9858e128230c3dd5439fd913ddcce5fe73e0649 Mon Sep 17 00:00:00 2001 From: Ankur Pawar Date: Thu, 9 Mar 2023 11:22:35 +0000 Subject: [PATCH] media: add ar0234 sensor driver Add ar0234 camera sensor driver code, max96712 GMSL serializer code, mode tables and makefile changes. These drivers are copied from K5.10 camera driver repo. Changes include svcacv warning fix and eeprom read status is ignored due to bug 4064490. Bug 3583587 Bug 4064490 Change-Id: I7ea0ecf959caccafd283c8db5fb7c3be912cf8bb Signed-off-by: Ankur Pawar Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2868422 Reviewed-by: Laxman Dewangan GVS: Gerrit_Virtual_Submit --- drivers/media/i2c/Makefile | 2 + drivers/media/i2c/ar0234_mode_tbls.h | 699 ++++++++++++++++ drivers/media/i2c/max96712.c | 274 +++++++ drivers/media/i2c/nv_ar0234.c | 1095 ++++++++++++++++++++++++++ include/media/gmsl-link.h | 103 +++ include/media/max9295.h | 87 ++ include/media/max9296.h | 151 ++++ 7 files changed, 2411 insertions(+) create mode 100644 drivers/media/i2c/ar0234_mode_tbls.h create mode 100644 drivers/media/i2c/max96712.c create mode 100644 drivers/media/i2c/nv_ar0234.c create mode 100644 include/media/gmsl-link.h create mode 100644 include/media/max9295.h create mode 100644 include/media/max9296.h diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index c89e79b6..f6a606e1 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -7,3 +7,5 @@ obj-m += nv_imx185.o obj-m += nv_imx274.o obj-m += nv_imx318.o obj-m += nv_ov5693.o +obj-m += max96712.o +obj-m += nv_ar0234.o diff --git a/drivers/media/i2c/ar0234_mode_tbls.h b/drivers/media/i2c/ar0234_mode_tbls.h new file mode 100644 index 00000000..b5f7daf1 --- /dev/null +++ b/drivers/media/i2c/ar0234_mode_tbls.h @@ -0,0 +1,699 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */ +/* + * ar0234_mode_tbls.h - ar0234 sensor mode tables + */ +#ifndef __AR0234_I2C_TABLES__ +#define __AR0234_I2C_TABLES__ + +#include + +#define AR0234_TABLE_WAIT_MS 0xff00 +#define AR0234_TABLE_END 0xff01 +#define AR0234_MAX_RETRIES 3 +#define AR0234_WAIT_MS_STOP 1 +#define AR0234_WAIT_MS_START 30 +#define AR0234_WAIT_MS_STREAM 210 +#define AR0234_GAIN_TABLE_SIZE 255 + +#define AR0234_EEPROM_ADDRESS 0x54 +#define AR0234_EEPROM_ADDRESS_R 0x58 +#define AR0234_EEPROM_SIZE 512 +#define AR0234_EEPROM_STR_SIZE (AR0234_EEPROM_SIZE * 2) +#define AR0234_EEPROM_BLOCK_SIZE (1 << 8) +#define AR0234_EEPROM_NUM_BLOCKS \ + (AR0234_EEPROM_SIZE / AR0234_EEPROM_BLOCK_SIZE) + + +#define ar0234_reg struct reg_16 + +struct index_reg_8 { + u16 source; + u16 addr; + u16 val; +}; + +static struct index_reg_8 ar0234_start[] = { + {0x06, 0x30ce, 0x0120}, + {0x06, 0x301A, 0x295C}, // RESET_REGISTER + + {0x00, AR0234_TABLE_END, 0x00} +}; + +static struct index_reg_8 ar0234_stop[] = { + {0x06, 0x301a, 0x2058}, + + {0x00, AR0234_TABLE_END, 0x00} +}; + +static struct index_reg_8 ar0234_Double_Dser_Ser[] = { + {0x52, 0x1458, 0x28}, + {0x52, 0x1459, 0x68}, + {0x52, 0x1558, 0x28}, + {0x52, 0x1559, 0x68}, + {0x52, 0x1658, 0x28}, + {0x52, 0x1659, 0x68}, + {0x52, 0x1758, 0x28}, + {0x52, 0x1759, 0x68}, + + {0x52, 0x0018, 0x0F}, // Oneshot reset + {0x52, 0x0006, 0xF3}, // Enable links A and B + {0x52, 0x0001, 0xcc}, // disable the i2c2 + + {0x52, 0x0003, 0xAE}, // Disable CC to link B + {0x80, 0x0000, 0x84}, // Link A serializer address is 0x84 + + {0x52, 0x0003, 0xAB}, // Disable CC to link A + {0x80, 0x0000, 0x88}, // Link B serializer address is 0x88 + {0x52, 0x0003, 0xAA}, // Enable CC to links A and B + {0x84, 0x0002, 0x33}, // Enable pipes X and Y + {0x84, 0x0308, 0x7E}, // Pipe X pulls clock from port A, pipe Y from port B + {0x84, 0x0311, 0x21}, // Pipe X pulls data from port A, pipe Y from port B + {0x84, 0x0316, 0x6b}, // RAW10 to pipe Y + {0x84, 0x0314, 0x6b}, // RAW10 to pipe Y + {0x88, 0x0002, 0x33}, // Enable pipes X and Y + {0x88, 0x0308, 0x7E}, // Pipe X pulls clock from port A, pipe Y from port B + {0x88, 0x0311, 0x21}, // Pipe X pulls data from port A, pipe Y from port B + {0x88, 0x0316, 0x6b}, // RAW10 to pipe Y + {0x88, 0x0314, 0x6b}, // RAW10 to pipe Y + {0x52, 0x00F4, 0x0f}, // Enable pipe 0 + {0x52, 0x00F0, 0x10}, // Link A ID 0 to pipe 0 // Link A ID 1 to pipe 1 + {0x52, 0x00F1, 0x54}, // Link B ID 0 to pipe 2 // Link B ID 1 to pipe 3 + + {0x52, 0x08A0, 0x01}, // CSI output is 2x4 + {0x52, 0x08A3, 0x44}, // Default 4x2 lane mapping + {0x52, 0x08A4, 0x44}, // Default 4x2 lane mapping + + {0x52, 0x090A, 0x40}, + {0x52, 0x094A, 0x40}, // 2 lanes on port D + {0x52, 0x098A, 0x40}, // 2 lanes on port E + {0x52, 0x09CA, 0x40}, + + {0x52, 0x1D00, 0xF4}, + {0x52, 0x1E00, 0xF4}, + + {0x52, 0x0415, 0x2E}, + {0x52, 0x0418, 0x2E}, // 1400Mbps + {0x52, 0x041B, 0x2E}, + {0x52, 0x041E, 0x2E}, + + {0x52, 0x1D00, 0xF5}, + {0x52, 0x1E00, 0xF5}, + + {0x52, 0x090B, 0x07}, // Enable 3 mappings Pipe 0//video2 + {0x52, 0x092D, 0x15}, // All mappings to controller 1 (port A) + {0x52, 0x090D, 0x2B}, // Input RAW10, VC0 + {0x52, 0x090E, 0x2B}, // Output RAW10, VC0 + {0x52, 0x090F, 0x00}, // Input FS, VC0 + {0x52, 0x0910, 0x00}, // Output FS, VC0 + {0x52, 0x0911, 0x01}, // Input FE, VC0 + {0x52, 0x0912, 0x01}, // Output FE, VC0 + + {0x52, 0x094B, 0x07}, // Enable 3 mappings Pipe 1 //video3 + {0x52, 0x096D, 0x15}, // All mappings to controller 1 (port A) + {0x52, 0x094D, 0x2B}, // Input RAW10, VC0 + {0x52, 0x094E, 0x6B}, // Output RAW10, VC1 + {0x52, 0x094F, 0x00}, // Input FS, VC0 + {0x52, 0x0950, 0x40}, // Output FS, VC1 + {0x52, 0x0951, 0x01}, // Input FE, VC0 + {0x52, 0x0952, 0x41}, // Output FE, VC1 + + {0x52, 0x098B, 0x07}, // Enable 3 mappings Pipe 2 //video1 + {0x52, 0x09AD, 0x15}, // All mappings to controller 1 (port A) + {0x52, 0x098D, 0x2B}, // Input RAW10, VC0 + {0x52, 0x098E, 0xaB}, // Output RAW10, VC2 + {0x52, 0x098F, 0x00}, // Input FS, VC0 + {0x52, 0x0990, 0x80}, // Output FS, VC2 + {0x52, 0x0991, 0x01}, // Input FE, VC0 + {0x52, 0x0992, 0x81}, // Output FE, VC2 + + {0x52, 0x09CB, 0x07}, // Enable 3 mappings Pipe 3 //video0 + {0x52, 0x09ED, 0x15}, // All mappings to controller 1 (port A) + {0x52, 0x09CD, 0x2B}, // Input RAW10, VC0 + {0x52, 0x09CE, 0xeB}, // Output RAW10, VC3 + {0x52, 0x09CF, 0x00}, // Input FS, VC0 + {0x52, 0x09D0, 0xc0}, // Output FS, VC3 + {0x52, 0x09D1, 0x01}, // Input FE, VC0 + {0x52, 0x09D2, 0xc1}, // Output FE, VC3 + + {0x52, 0x08A2, 0xF0}, + {0x84, 0x02be, 0x90}, // Enable sensor power down pin. + {0x84, 0x02bf, 0x60}, // Enable sensor reset pin. + {0x84, 0x02ca, 0x80}, // Enable sensor power down pin. + {0x84, 0x02cb, 0x60}, // Enable sensor reset pin. + {0x84, 0x02d3, 0x90}, // Enable sensor power down pin. + {0x84, 0x02d4, 0x60}, // Enable sensor reset pin. + {0x84, 0x02d6, 0x90}, // Enable sensor power down pin. + {0x84, 0x02d7, 0x60}, // Enable sensor reset pin. + {0x88, 0x02be, 0x90}, // Enable sensor power down pin. + {0x88, 0x02bf, 0x60}, // Enable sensor reset pin. + {0x88, 0x02ca, 0x80}, // Enable sensor power down pin. + {0x88, 0x02cb, 0x60}, // Enable sensor reset pin. + {0x88, 0x02d3, 0x90}, // Enable sensor power down pin. + {0x88, 0x02d4, 0x60}, // Enable sensor reset pin. + {0x88, 0x02d6, 0x90}, // Enable sensor power down pin. + {0x88, 0x02d7, 0x60}, // Enable sensor reset pin. + + + {0x52, 0x04AF, 0xC0}, // AUTO_FS_LINKS = 0, FS_USE_XTAL = 1, FS_LINK_[3:0] = 0 + {0x52, 0x04A0, 0x00}, // Manual frame sync, no pin output + + {0x52, 0x04A2, 0x00}, // Turn off auto master link selection + {0x52, 0x04AA, 0x00}, // OVLP window = 0 + {0x52, 0x04AB, 0x00}, + + {0x52, 0x04A5, 0x35}, // 30Hz FSYNC + {0x52, 0x04A6, 0xB7}, + {0x52, 0x04A7, 0x0C}, + + {0x84, 0x02D9, 0x04}, + {0x84, 0x02DB, 0x08}, + {0x84, 0x02Dc, 0x04}, + {0x84, 0x02De, 0x08}, // MFP8 for FSIN + + {0x88, 0x02D9, 0x04}, + {0x88, 0x02DB, 0x08}, + {0x88, 0x02Dc, 0x04}, + {0x88, 0x02De, 0x08}, // MFP8 for FSIN + + {0x52, 0x04B1, 0x40}, // FSYNC TX ID is 8 + + {0x84, 0x0042, 0xB0}, // eeprom i2c map + {0x84, 0x0043, 0xA8}, + {0x84, 0x0044, 0xB2}, + {0x84, 0x0045, 0xAA}, + + {0x88, 0x0042, 0xB0}, // eeprom i2c map + {0x88, 0x0043, 0xA8}, + {0x88, 0x0044, 0xB2}, + {0x88, 0x0045, 0xAA}, + + {0x84, 0x02be, 0x83}, // hawk1(0x84) max9295D MFP0-- ACCEL interrupt + {0x84, 0x02bf, 0x11}, + {0x52, 0x030c, 0x04}, // max96712 MTF4---ACCEL1 interrupt + {0x52, 0x030e, 0x11}, // MTF4 + + {0x84, 0x02c7, 0x83}, // hawk1(0x84)max9295D MFP3-- gyro interrupt + {0x84, 0x02c8, 0x12}, + {0x52, 0x0320, 0x04}, // max96712 MTF10---gyro1 interrupt + {0x52, 0x0322, 0x12}, // MTF10 + + // Disable output, enable TX hawk2(0x88) max9295D MFP0-- ACCEL interrupt + {0x88, 0x02BE, 0x03}, + {0x88, 0x02BF, 0x00}, // No pull-up/down, TX ID = 0 + {0x52, 0x0310, 0x00}, // Enable output max96712 MTF5---ACCEL2 interrupt + {0x52, 0x0347, 0x05}, // Disable TX on link B + {0x52, 0x0348, 0x60}, // Enable RX on link B, RX ID = 0 + + {0x88, 0x02c7, 0x03}, // hawk2(0x88)max9295D MFP3-- gyro interrupt + {0x88, 0x02c8, 0x15}, + {0x52, 0x0313, 0x00}, + {0x52, 0x034A, 0x05}, // max96712 MTF6---gyro2 interrupt + {0x52, 0x034B, 0x75}, // MTF6 + + {0x52, 0x0003, 0xFF}, // enable i2c channel B + {0x52, 0x0007, 0x20}, + {0x52, 0x0003, 0xF6}, + + {0x00, AR0234_TABLE_END, 0x00 } +}; + + + +static struct index_reg_8 ar0234_Single_Dser_Ser[] = { + {0x52, 0x1458, 0x28}, + {0x52, 0x1459, 0x68}, + {0x52, 0x1558, 0x28}, + {0x52, 0x1559, 0x68}, + {0x52, 0x1658, 0x28}, + {0x52, 0x1659, 0x68}, + {0x52, 0x1758, 0x28}, + {0x52, 0x1759, 0x68}, + + {0x52, 0x0018, 0x0F}, + {0x52, 0x0006, 0xF1}, + {0x52, 0x0001, 0xcc}, // disable the i2c2 + {0x80, 0x0010, 0x21}, + {0x80, 0x0330, 0x06}, + {0x80, 0x0332, 0x4E}, + {0x80, 0x0333, 0xE4}, + {0x80, 0x0331, 0x77}, + {0x80, 0x0311, 0x41}, + {0x80, 0x0308, 0x74}, + {0x80, 0x0314, 0x2B}, + {0x80, 0x0316, 0x22}, + {0x80, 0x0318, 0x2B}, + {0x80, 0x031A, 0x22}, + {0x80, 0x0002, 0xff}, + {0x80, 0x0053, 0x10}, + {0x80, 0x0057, 0x11}, + {0x80, 0x005B, 0x12}, + {0x80, 0x005F, 0x13}, + + {0x52, 0x00F0, 0x20}, // pipx--pip0 pipz--pip1 gmsl phy A + + {0x52, 0x00F4, 0x03}, // enable pip 0/1 + + {0x52, 0x08A0, 0x01}, + {0x52, 0x08A3, 0x44}, + {0x52, 0x08A4, 0x44}, + {0x52, 0x090A, 0x40}, + {0x52, 0x094A, 0x40}, + {0x52, 0x098A, 0x40}, + {0x52, 0x09CA, 0x40}, + {0x52, 0x0415, 0x2E}, + {0x52, 0x0418, 0x2E}, + {0x52, 0x041B, 0x2E}, + {0x52, 0x041E, 0x2E}, + + {0x52, 0x090B, 0x07}, + {0x52, 0x092D, 0x15}, + {0x52, 0x090D, 0x2b}, + {0x52, 0x090E, 0x2b}, + {0x52, 0x090F, 0x00}, + {0x52, 0x0910, 0x00}, + {0x52, 0x0911, 0x01}, + {0x52, 0x0912, 0x01}, + + {0x52, 0x094B, 0x07}, + {0x52, 0x096D, 0x15}, + {0x52, 0x094D, 0x2b}, + {0x52, 0x094E, 0x6b}, + {0x52, 0x094F, 0x00}, + {0x52, 0x0950, 0x40}, + {0x52, 0x0951, 0x01}, + {0x52, 0x0952, 0x41}, + + {0x80, 0x02be, 0x90}, // Enable sensor power down pin. + {0x80, 0x02bf, 0x60}, // Enable sensor reset pin. + {0x80, 0x02ca, 0x80}, // Enable sensor power down pin. + {0x80, 0x02cb, 0x60}, // Enable sensor reset pin. + {0x80, 0x02d3, 0x90}, // Enable sensor power down pin. + {0x80, 0x02d4, 0x60}, // Enable sensor reset pin. + {0x80, 0x02d6, 0x90}, // Enable sensor power down pin. + {0x80, 0x02d7, 0x60}, // Enable sensor reset pin. + + {0x52, 0x04AF, 0xC0}, // AUTO_FS_LINKS = 0, FS_USE_XTAL = 1, FS_LINK_[3:0] = 0 + {0x52, 0x04A0, 0x04}, // Manual frame sync, output on MFP2 + {0x52, 0x04A2, 0x00}, // Turn off auto master link selection + {0x52, 0x04AA, 0x00}, // OVLP window = 0 + {0x52, 0x04AB, 0x00}, + {0x52, 0x04A5, 0x35}, // 30Hz FSYNC + {0x52, 0x04A6, 0xB7}, + {0x52, 0x04A7, 0x0C}, + + {0x80, 0x02D9, 0x04}, + {0x80, 0x02DB, 0x08}, // MFP8 for FSIN + {0x80, 0x02Dc, 0x04}, + {0x80, 0x02De, 0x08}, // MFP8 for FSIN + {0x52, 0x04B1, 0x40}, // FSYNC TX ID is 8 + + {0x80, 0x0042, 0xB0}, // eeprom i2c map eeporm have two i2c address + {0x80, 0x0043, 0xA8}, + {0x80, 0x0044, 0xB2}, + {0x80, 0x0045, 0xAA}, + + {0x80, 0x02be, 0x83}, // hawk1(0x84) max9295D MFP0-- ACCEL interrupt + {0x80, 0x02bf, 0x11}, + {0x52, 0x030c, 0x04}, // max96712 MTF4---ACCEL1 interrupt + {0x52, 0x030e, 0x11}, // MTF4 + + {0x80, 0x02c7, 0x83}, // hawk1(0x84)max9295D MFP3-- gyro interrupt + {0x80, 0x02c8, 0x12}, + {0x52, 0x0320, 0x04}, // max96712 MTF10---gyro1 interrupt + {0x52, 0x0322, 0x12}, // MTF10 + + {0x00, AR0234_TABLE_END, 0x00 } +}; + +static struct index_reg_8 ar0234_1920x1080_crop_30fps[] = { + {0x06, 0x301A, 0x00D9}, + {0x06, AR0234_TABLE_WAIT_MS, 100}, + + {0x06, 0x3F4C, 0x121F}, + {0x06, 0x3F4E, 0x121F}, + {0x06, 0x3F50, 0x0B81}, + {0x06, 0x31E0, 0x0003}, + {0x06, 0x31E0, 0x0003}, + {0x06, 0x30B0, 0x0028}, + {0x06, 0x3088, 0x8000}, + {0x06, 0x3086, 0xC1AE}, + {0x06, 0x3086, 0x327F}, + {0x06, 0x3086, 0x5780}, + {0x06, 0x3086, 0x272F}, + {0x06, 0x3086, 0x7416}, + {0x06, 0x3086, 0x7E13}, + {0x06, 0x3086, 0x8000}, + {0x06, 0x3086, 0x307E}, + {0x06, 0x3086, 0xFF80}, + {0x06, 0x3086, 0x20C3}, + {0x06, 0x3086, 0xB00E}, + {0x06, 0x3086, 0x8190}, + {0x06, 0x3086, 0x1643}, + {0x06, 0x3086, 0x1651}, + {0x06, 0x3086, 0x9D3E}, + {0x06, 0x3086, 0x9545}, + {0x06, 0x3086, 0x2209}, + {0x06, 0x3086, 0x3781}, + {0x06, 0x3086, 0x9016}, + {0x06, 0x3086, 0x4316}, + {0x06, 0x3086, 0x7F90}, + {0x06, 0x3086, 0x8000}, + {0x06, 0x3086, 0x387F}, + {0x06, 0x3086, 0x1380}, + {0x06, 0x3086, 0x233B}, + {0x06, 0x3086, 0x7F93}, + {0x06, 0x3086, 0x4502}, + {0x06, 0x3086, 0x8000}, + {0x06, 0x3086, 0x7FB0}, + {0x06, 0x3086, 0x8D66}, + {0x06, 0x3086, 0x7F90}, + {0x06, 0x3086, 0x8192}, + {0x06, 0x3086, 0x3C16}, + {0x06, 0x3086, 0x357F}, + {0x06, 0x3086, 0x9345}, + {0x06, 0x3086, 0x0280}, + {0x06, 0x3086, 0x007F}, + {0x06, 0x3086, 0xB08D}, + {0x06, 0x3086, 0x667F}, + {0x06, 0x3086, 0x9081}, + {0x06, 0x3086, 0x8237}, + {0x06, 0x3086, 0x4502}, + {0x06, 0x3086, 0x3681}, + {0x06, 0x3086, 0x8044}, + {0x06, 0x3086, 0x1631}, + {0x06, 0x3086, 0x4374}, + {0x06, 0x3086, 0x1678}, + {0x06, 0x3086, 0x7B7D}, + {0x06, 0x3086, 0x4502}, + {0x06, 0x3086, 0x450A}, + {0x06, 0x3086, 0x7E12}, + {0x06, 0x3086, 0x8180}, + {0x06, 0x3086, 0x377F}, + {0x06, 0x3086, 0x1045}, + {0x06, 0x3086, 0x0A0E}, + {0x06, 0x3086, 0x7FD4}, + {0x06, 0x3086, 0x8024}, + {0x06, 0x3086, 0x0E82}, + {0x06, 0x3086, 0x9CC2}, + {0x06, 0x3086, 0xAFA8}, + {0x06, 0x3086, 0xAA03}, + {0x06, 0x3086, 0x430D}, + {0x06, 0x3086, 0x2D46}, + {0x06, 0x3086, 0x4316}, + {0x06, 0x3086, 0x5F16}, + {0x06, 0x3086, 0x530D}, + {0x06, 0x3086, 0x1660}, + {0x06, 0x3086, 0x401E}, + {0x06, 0x3086, 0x2904}, + {0x06, 0x3086, 0x2984}, + {0x06, 0x3086, 0x81E7}, + {0x06, 0x3086, 0x816F}, + {0x06, 0x3086, 0x1706}, + {0x06, 0x3086, 0x81E7}, + {0x06, 0x3086, 0x7F81}, + {0x06, 0x3086, 0x5C0D}, + {0x06, 0x3086, 0x5754}, + {0x06, 0x3086, 0x495F}, + {0x06, 0x3086, 0x5305}, + {0x06, 0x3086, 0x5307}, + {0x06, 0x3086, 0x4D2B}, + {0x06, 0x3086, 0xF810}, + {0x06, 0x3086, 0x164C}, + {0x06, 0x3086, 0x0755}, + {0x06, 0x3086, 0x562B}, + {0x06, 0x3086, 0xB82B}, + {0x06, 0x3086, 0x984E}, + {0x06, 0x3086, 0x1129}, + {0x06, 0x3086, 0x9460}, + {0x06, 0x3086, 0x5C09}, + {0x06, 0x3086, 0x5C1B}, + {0x06, 0x3086, 0x4002}, + {0x06, 0x3086, 0x4500}, + {0x06, 0x3086, 0x4580}, + {0x06, 0x3086, 0x29B6}, + {0x06, 0x3086, 0x7F80}, + {0x06, 0x3086, 0x4004}, + {0x06, 0x3086, 0x7F88}, + {0x06, 0x3086, 0x4109}, + {0x06, 0x3086, 0x5C0B}, + {0x06, 0x3086, 0x29B2}, + {0x06, 0x3086, 0x4115}, + {0x06, 0x3086, 0x5C03}, + {0x06, 0x3086, 0x4105}, + {0x06, 0x3086, 0x5F2B}, + {0x06, 0x3086, 0x902B}, + {0x06, 0x3086, 0x8081}, + {0x06, 0x3086, 0x6F40}, + {0x06, 0x3086, 0x1041}, + {0x06, 0x3086, 0x0160}, + {0x06, 0x3086, 0x29A2}, + {0x06, 0x3086, 0x29A3}, + {0x06, 0x3086, 0x5F4D}, + {0x06, 0x3086, 0x1C17}, + {0x06, 0x3086, 0x0281}, + {0x06, 0x3086, 0xE729}, + {0x06, 0x3086, 0x8345}, + {0x06, 0x3086, 0x8840}, + {0x06, 0x3086, 0x0F7F}, + {0x06, 0x3086, 0x8A40}, + {0x06, 0x3086, 0x2345}, + {0x06, 0x3086, 0x8024}, + {0x06, 0x3086, 0x4008}, + {0x06, 0x3086, 0x7F88}, + {0x06, 0x3086, 0x5D29}, + {0x06, 0x3086, 0x9288}, + {0x06, 0x3086, 0x102B}, + {0x06, 0x3086, 0x0489}, + {0x06, 0x3086, 0x165C}, + {0x06, 0x3086, 0x4386}, + {0x06, 0x3086, 0x170B}, + {0x06, 0x3086, 0x5C03}, + {0x06, 0x3086, 0x8A48}, + {0x06, 0x3086, 0x4D4E}, + {0x06, 0x3086, 0x2B80}, + {0x06, 0x3086, 0x4C09}, + {0x06, 0x3086, 0x4119}, + {0x06, 0x3086, 0x816F}, + {0x06, 0x3086, 0x4110}, + {0x06, 0x3086, 0x4001}, + {0x06, 0x3086, 0x6029}, + {0x06, 0x3086, 0x8229}, + {0x06, 0x3086, 0x8329}, + {0x06, 0x3086, 0x435C}, + {0x06, 0x3086, 0x055F}, + {0x06, 0x3086, 0x4D1C}, + {0x06, 0x3086, 0x81E7}, + {0x06, 0x3086, 0x4502}, + {0x06, 0x3086, 0x8180}, + {0x06, 0x3086, 0x7F80}, + {0x06, 0x3086, 0x410A}, + {0x06, 0x3086, 0x9144}, + {0x06, 0x3086, 0x1609}, + {0x06, 0x3086, 0x2FC3}, + {0x06, 0x3086, 0xB130}, + {0x06, 0x3086, 0xC3B1}, + {0x06, 0x3086, 0x0343}, + {0x06, 0x3086, 0x164A}, + {0x06, 0x3086, 0x0A43}, + {0x06, 0x3086, 0x160B}, + {0x06, 0x3086, 0x4316}, + {0x06, 0x3086, 0x8F43}, + {0x06, 0x3086, 0x1690}, + {0x06, 0x3086, 0x4316}, + {0x06, 0x3086, 0x7F81}, + {0x06, 0x3086, 0x450A}, + {0x06, 0x3086, 0x410F}, + {0x06, 0x3086, 0x7F83}, + {0x06, 0x3086, 0x5D29}, + {0x06, 0x3086, 0x4488}, + {0x06, 0x3086, 0x102B}, + {0x06, 0x3086, 0x0453}, + {0x06, 0x3086, 0x0D40}, + {0x06, 0x3086, 0x2345}, + {0x06, 0x3086, 0x0240}, + {0x06, 0x3086, 0x087F}, + {0x06, 0x3086, 0x8053}, + {0x06, 0x3086, 0x0D89}, + {0x06, 0x3086, 0x165C}, + {0x06, 0x3086, 0x4586}, + {0x06, 0x3086, 0x170B}, + {0x06, 0x3086, 0x5C05}, + {0x06, 0x3086, 0x8A60}, + {0x06, 0x3086, 0x4B91}, + {0x06, 0x3086, 0x4416}, + {0x06, 0x3086, 0x09C1}, + {0x06, 0x3086, 0x2CA9}, + {0x06, 0x3086, 0xAB30}, + {0x06, 0x3086, 0x51B3}, + {0x06, 0x3086, 0x3D5A}, + {0x06, 0x3086, 0x7E3D}, + {0x06, 0x3086, 0x7E19}, + {0x06, 0x3086, 0x8000}, + {0x06, 0x3086, 0x8B1F}, + {0x06, 0x3086, 0x2A1F}, + {0x06, 0x3086, 0x83A2}, + {0x06, 0x3086, 0x7516}, + {0x06, 0x3086, 0xAD33}, + {0x06, 0x3086, 0x450A}, + {0x06, 0x3086, 0x7F53}, + {0x06, 0x3086, 0x8023}, + {0x06, 0x3086, 0x8C66}, + {0x06, 0x3086, 0x7F13}, + {0x06, 0x3086, 0x8184}, + {0x06, 0x3086, 0x1481}, + {0x06, 0x3086, 0x8031}, + {0x06, 0x3086, 0x3D64}, + {0x06, 0x3086, 0x452A}, + {0x06, 0x3086, 0x9451}, + {0x06, 0x3086, 0x9E96}, + {0x06, 0x3086, 0x3D2B}, + {0x06, 0x3086, 0x3D1B}, + {0x06, 0x3086, 0x529F}, + {0x06, 0x3086, 0x0E3D}, + {0x06, 0x3086, 0x083D}, + {0x06, 0x3086, 0x167E}, + {0x06, 0x3086, 0x307E}, + {0x06, 0x3086, 0x1175}, + {0x06, 0x3086, 0x163E}, + {0x06, 0x3086, 0x970E}, + {0x06, 0x3086, 0x82B2}, + {0x06, 0x3086, 0x3D7F}, + {0x06, 0x3086, 0xAC3E}, + {0x06, 0x3086, 0x4502}, + {0x06, 0x3086, 0x7E11}, + {0x06, 0x3086, 0x7FD0}, + {0x06, 0x3086, 0x8000}, + {0x06, 0x3086, 0x8C66}, + {0x06, 0x3086, 0x7F90}, + {0x06, 0x3086, 0x8194}, + {0x06, 0x3086, 0x3F44}, + {0x06, 0x3086, 0x1681}, + {0x06, 0x3086, 0x8416}, + {0x06, 0x3086, 0x2C2C}, + {0x06, 0x3086, 0x2C2C}, + {0x06, 0x302A, 0x0005}, + {0x06, 0x302C, 0x0001}, + {0x06, 0x302E, 0x0003}, + {0x06, 0x3030, 0x0096}, // PLL multiplier + {0x06, 0x302E, 0x0006}, // PLL input pre-divider value + {0x06, 0x302C, 0x0004}, // P1 divider + {0x06, 0x302A, 0x0005}, // P2 divider + {0x06, 0x3038, 0x0004}, // P3 divider + {0x06, 0x3036, 0x000A}, // WCD divider + {0x06, 0x31B0, 0x002F}, // Frame preamble + {0x06, 0x31B2, 0x002C}, // Line preamble + {0x06, 0x31B4, 0x1144}, // MIPI timing 0 + {0x06, 0x31B6, 0x00C7}, // MIPI timing 1 + {0x06, 0x31B8, 0x3047}, // MIPI timing 2 + {0x06, 0x31BA, 0x0103}, // MIPI timing 3 + {0x06, 0x31BC, 0x8583}, // MIPI timing 4 + {0x06, 0x31AE, 0x0204}, // 4-lane MIPI + {0x06, 0x3002, 0x0008}, // Y_ADDR_START = 8 + {0x06, 0x3004, 0x0008}, // X_ADDR_START = 8 + {0x06, 0x3006, 0x04B7}, // Y_ADDR_END = 1207 + {0x06, 0x3008, 0x0787}, // X_ADDR_END = 1927 + {0x06, 0x300A, 0x04C6}, // FRAME_LENGTH_LINES = 1220 + {0x06, 0x300C, 0x0264}, // LINE_LENGTH_PCK = 612 + {0x06, 0x3012, 0x02DC}, // COARSE_INTEGRATION_TIME = 732 + {0x06, 0x31AC, 0x0A0A}, // DATA_FORMAT_BITS = 2570 + {0x06, 0x306E, 0x9010}, // DATAPATH_SELECT = 36880 + {0x06, 0x30A2, 0x0001}, // X_ODD_INC = 1 + {0x06, 0x30A6, 0x0001}, // Y_ODD_INC = 1 + {0x06, 0x3082, 0x0003}, // OPERATION_MODE_CTRL = 3 + {0x06, 0x3040, 0x0000}, // READ_MODE = 0 + {0x06, 0x31D0, 0x0000}, // COMPANDING = 0 + + {0x06, 0x3044, 0x0410}, + {0x06, 0x3094, 0x03D4}, + {0x06, 0x3096, 0x0480}, + {0x06, 0x30BA, 0x7602}, + {0x06, 0x30B0, 0x0028}, + {0x06, 0x30FE, 0x002A}, + {0x06, 0x31DE, 0x0410}, + {0x06, 0x3ED6, 0x1435}, + {0x06, 0x3ED8, 0x9865}, + {0x06, 0x3EDA, 0x7698}, + {0x06, 0x3EDC, 0x99FF}, + {0x06, 0x3EE2, 0xBB88}, + {0x06, 0x3EE4, 0x8836}, + {0x06, 0x3EF0, 0x1CF0}, + {0x06, 0x3EF2, 0x0000}, + {0x06, 0x3EF8, 0x6166}, + {0x06, 0x3EFA, 0x3333}, + {0x06, 0x3EFC, 0x6634}, + {0x06, 0x3276, 0x05DC}, + {0x06, 0x3F00, 0x9D05}, + {0x06, 0x3ED2, 0xFA86}, + {0x06, 0x3EEE, 0xA4FE}, + {0x06, 0x30BA, 0x7602}, + {0x06, 0x3180, 0xC24F}, + {0x06, 0x3ECC, 0x6E42}, + {0x06, 0x3ECC, 0x0E42}, + {0x06, 0x3EEC, 0x0C0C}, + {0x06, 0x3EE8, 0xAAE4}, + {0x06, 0x3EE6, 0x3363}, + {0x06, 0x3EE6, 0x3363}, + {0x06, 0x3EE8, 0xAAE4}, + {0x06, 0x3EE8, 0xAAE4}, + {0x06, 0x3102, 0x5000}, + {0x06, 0x3060, 0x000D}, + {0x06, 0x3ED0, 0xFF44}, + {0x06, 0x3ED2, 0xAA86}, + {0x06, 0x3ED4, 0x031F}, + {0x06, 0x3EEE, 0xA4AA}, + {0x06, 0x301a, 0x2058}, + + {0x00, AR0234_TABLE_END, 0x00}, +}; + +static struct index_reg_8 tp_colorbars[] = { + {0x06, 0x3070, 0x2}, + + {0x00, AR0234_TABLE_END, 0x00}, +}; + +enum { + AR0234_MODE_1920X1080_CROP_30FPS, + AR0234_MODE_START_STREAM, + AR0234_MODE_STOP_STREAM, + AR0234_MODE_Dser_Ser, + AR0234_MODE_Single_Dser_Ser, + AR0234_MODE_TEST_PATTERN +}; + +static struct index_reg_8 *mode_table[] = { + [AR0234_MODE_1920X1080_CROP_30FPS] + = ar0234_1920x1080_crop_30fps, + [AR0234_MODE_START_STREAM] + = ar0234_start, + [AR0234_MODE_STOP_STREAM] + = ar0234_stop, + [AR0234_MODE_Dser_Ser] = ar0234_Double_Dser_Ser, + [AR0234_MODE_Single_Dser_Ser] = ar0234_Single_Dser_Ser, + [AR0234_MODE_TEST_PATTERN] = tp_colorbars, + +}; + +static const int ar0234_30fps[] = { + 30, +}; + +static const int ar0234_36fps[] = { + 36, +}; + +static const int ar0234_18fps[] = { + 18, +}; +static const int ar0234_60fps[] = { + 60, +}; + +static const int ar0234_120fps[] = { + 120, +}; +static const struct camera_common_frmfmt ar0234_frmfmt[] = { + {{1920, 1200}, ar0234_60fps, 1, 0, AR0234_MODE_1920X1080_CROP_30FPS}, +}; +#endif /* __AR0234_I2C_TABLES__ */ diff --git a/drivers/media/i2c/max96712.c b/drivers/media/i2c/max96712.c new file mode 100644 index 00000000..0f8fcefa --- /dev/null +++ b/drivers/media/i2c/max96712.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * max96712.c - max96712 IO Expander driver + * + * Copyright (c) 2016-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. + */ + +/* #define DEBUG */ + +#include +#include +#include +#include + + +struct max96712 { + struct i2c_client *i2c_client; + struct regmap *regmap; + const char *channel; +}; +static struct max96712 *global_priv[4]; + +int max96712_write_reg_Dser(int slaveAddr, int channel, u16 addr, u8 val); +int max96712_read_reg_Dser(int slaveAddr, int channel, u16 addr, unsigned int *val); + +int max96712_write_reg_Dser(int slaveAddr, int channel, + u16 addr, u8 val) +{ + struct i2c_client *i2c_client = NULL; + int bak = 0; + int err; + /* unsigned int ival = 0; */ + + if (channel > 3 || channel < 0 || global_priv[channel] == NULL) + return -1; + i2c_client = global_priv[channel]->i2c_client; + bak = i2c_client->addr; + + i2c_client->addr = slaveAddr / 2; + err = regmap_write(global_priv[channel]->regmap, addr, val); + + i2c_client->addr = bak; + if (err) { + dev_err(&i2c_client->dev, "%s: addr = 0x%x, val = 0x%x\n", + __func__, addr, val); + return -1; + } + return 0; +} +EXPORT_SYMBOL(max96712_write_reg_Dser); + + +int max96712_read_reg_Dser(int slaveAddr, int channel, + u16 addr, unsigned int *val) +{ + struct i2c_client *i2c_client = NULL; + int bak = 0; + int err; + + if (channel > 3 || channel < 0 || global_priv[channel] == NULL) + return -1; + + i2c_client = global_priv[channel]->i2c_client; + bak = i2c_client->addr; + i2c_client->addr = slaveAddr / 2; + + err = regmap_read(global_priv[channel]->regmap, addr, val); + i2c_client->addr = bak; + if (err) { + dev_err(&i2c_client->dev, "%s: addr = 0x%x, val = 0x%x\n", + __func__, addr, *val); + return -1; + } + return 0; + +} +EXPORT_SYMBOL(max96712_read_reg_Dser); + +static int max96712_read_reg(struct max96712 *priv, + u16 addr, unsigned int *val) +{ + struct i2c_client *i2c_client = priv->i2c_client; + int err; + + err = regmap_read(priv->regmap, addr, val); + if (err) + dev_err(&i2c_client->dev, "%s:i2c read failed, 0x%x = %x\n", + __func__, addr, *val); + + return err; +} + + +static int max96712_stats_show(struct seq_file *s, void *data) +{ + return 0; +} + +static int max96712_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, max96712_stats_show, inode->i_private); +} + +static ssize_t max96712_debugfs_write(struct file *s, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct max96712 *priv = + ((struct seq_file *)s->private_data)->private; + struct i2c_client *i2c_client = priv->i2c_client; + + char buf[255]; + int buf_size; + int val = 0; + + if (!user_buf || count <= 1) + return -EFAULT; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + if (buf[0] == 'd') { + dev_info(&i2c_client->dev, "%s, set daymode\n", __func__); + max96712_read_reg(priv, 0x0010, &val); + return count; + } + + if (buf[0] == 'n') { + dev_info(&i2c_client->dev, "%s, set nightmode\n", __func__); + return count; + } + + return count; +} + + +static const struct file_operations max96712_debugfs_fops = { + .open = max96712_debugfs_open, + .read = seq_read, + .write = max96712_debugfs_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static int max96712_debugfs_init(const char *dir_name, + struct dentry **d_entry, + struct dentry **f_entry, + struct max96712 *priv) +{ + struct dentry *dp, *fp; + char dev_name[20]; + struct i2c_client *i2c_client = priv->i2c_client; + struct device_node *np = i2c_client->dev.of_node; + int err = 0; + int index = 0; + + if (np) { + err = of_property_read_string(np, "channel", &priv->channel); + if (err) + dev_err(&i2c_client->dev, "channel not found\n"); + + err = snprintf(dev_name, sizeof(dev_name), "max96712_%s", priv->channel); + if (err < 0) + return -EINVAL; + } + index = priv->channel[0] - 'a'; + if (index < 0) + return -EINVAL; + global_priv[index] = priv; + + dev_dbg(&i2c_client->dev, "%s: index %d\n", __func__, index); + + dp = debugfs_create_dir(dev_name, NULL); + if (dp == NULL) { + dev_err(&i2c_client->dev, "%s: debugfs create dir failed\n", + __func__); + return -ENOMEM; + } + + fp = debugfs_create_file("max96712", 0644, dp, priv, + &max96712_debugfs_fops); + if (!fp) { + dev_err(&i2c_client->dev, "%s: debugfs create file failed\n", + __func__); + debugfs_remove_recursive(dp); + return -ENOMEM; + } + + if (d_entry) + *d_entry = dp; + if (f_entry) + *f_entry = fp; + return 0; +} + +static struct regmap_config max96712_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, +}; + +static int max96712_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct max96712 *priv; + int err = 0; + + dev_info(&client->dev, "%s: enter\n", __func__); + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + priv->i2c_client = client; + priv->regmap = devm_regmap_init_i2c(priv->i2c_client, + &max96712_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(&client->dev, + "regmap init failed: %ld\n", PTR_ERR(priv->regmap)); + return -ENODEV; + } + + err = max96712_debugfs_init(NULL, NULL, NULL, priv); + if (err) + return err; + + /*set daymode by fault*/ + dev_info(&client->dev, "%s: success\n", __func__); + + return err; +} + +#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE) +static int max96712_remove(struct i2c_client *client) +#else +static void max96712_remove(struct i2c_client *client) +#endif +{ + + if (client != NULL) { + i2c_unregister_device(client); + client = NULL; + } +#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE) + return 0; +#endif +} + +static const struct i2c_device_id max96712_id[] = { + { "max96712", 0 }, + { }, +}; + +static const struct of_device_id max96712_of_match[] = { + { .compatible = "nvidia,max96712", }, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, max96712_id); + +static struct i2c_driver max96712_i2c_driver = { + .driver = { + .name = "max96712", + .owner = THIS_MODULE, + }, + .probe = max96712_probe, + .remove = max96712_remove, + .id_table = max96712_id, +}; + +module_i2c_driver(max96712_i2c_driver); + +MODULE_DESCRIPTION("IO Expander driver max96712"); +MODULE_AUTHOR("NVIDIA Corporation"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/nv_ar0234.c b/drivers/media/i2c/nv_ar0234.c new file mode 100644 index 00000000..625ddbff --- /dev/null +++ b/drivers/media/i2c/nv_ar0234.c @@ -0,0 +1,1095 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. +/* + * ar0234.c - ar0234 sensor driver + */ + +#define DEBUG 1 +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include "ar0234_mode_tbls.h" + +#define CHANNEL_N 13 +#define MAX_RADIAL_COEFFICIENTS 6 +#define MAX_TANGENTIAL_COEFFICIENTS 2 +#define MAX_FISHEYE_COEFFICIENTS 6 +#define CAMERA_MAX_SN_LENGTH 32 +#define MAX_RLS_COLOR_CHANNELS 4 +#define MAX_RLS_BREAKPOINTS 6 + +extern int max96712_write_reg_Dser(int slaveAddr, int channel, + u16 addr, u8 val); + +extern int max96712_read_reg_Dser(int slaveAddr, int channel, + u16 addr, unsigned int *val); + +#define AR0234_MIN_GAIN (1) +#define AR0234_MAX_GAIN (8) +#define AR0234_MAX_GAIN_REG (0x40) +#define AR0234_DEFAULT_FRAME_LENGTH (1224) +#define AR0234_COARSE_TIME_SHS1_ADDR 0x3012 +#define AR0234_ANALOG_GAIN 0x3060 + +const struct of_device_id ar0234_of_match[] = { + {.compatible = "onsemi,ar0234",}, + { }, +}; +MODULE_DEVICE_TABLE(of, ar0234_of_match); + +static const u32 ctrl_cid_list[] = { + TEGRA_CAMERA_CID_GAIN, + TEGRA_CAMERA_CID_EXPOSURE, + TEGRA_CAMERA_CID_EXPOSURE_SHORT, + TEGRA_CAMERA_CID_FRAME_RATE, + TEGRA_CAMERA_CID_EEPROM_DATA, + TEGRA_CAMERA_CID_HDR_EN, + TEGRA_CAMERA_CID_SENSOR_MODE_ID, + TEGRA_CAMERA_CID_STEREO_EEPROM, +}; + +// Coefficients as per distortion model (wide FOV) being used +struct fisheye_lens_distortion_coeff { + // Radial coefficients count + u32 coeff_count; + // Radial coefficients + float k[MAX_FISHEYE_COEFFICIENTS]; + // 0 -> equidistant, 1 -> equisolid, 2 -> orthographic, 3 -> stereographic + u32 mapping_type; +}; + +// Coefficients as per distortion model being used +struct polynomial_lens_distortion_coeff { + // Radial coefficients count + u32 radial_coeff_count; + // Radial coefficients + float k[MAX_RADIAL_COEFFICIENTS]; + // Tangential coefficients count + u32 tangential_coeff_count; + // Tangential coefficients + float p[MAX_TANGENTIAL_COEFFICIENTS]; +}; + +/* + * Stereo Eeprom Data + */ +struct camera_intrinsics { + // Width and height of image in pixels + u32 width, height; + // Focal length in pixels + float fx, fy; + float skew; + // Principal point (optical center) in pixels + float cx, cy; + /* + * Structure for distortion coefficients as per the model being used + * 0: pinhole, assuming polynomial distortion + * 1: fisheye, assuming fisheye distortion) + * 2: ocam (omini-directional) + */ + u32 distortion_type; + union distortion_coefficients { + struct polynomial_lens_distortion_coeff poly; + struct fisheye_lens_distortion_coeff fisheye; + } dist_coeff; +}; + +/* + * Extrinsic parameters shared by camera and IMU. + * All rotation + translation with respect to the same reference point + */ +struct camera_extrinsics { + /* + * Rotation parameter expressed in Rodrigues notation + * angle = sqrt(rx^2+ry^2+rz^2) + * unit axis = [rx,ry,rz]/angle + */ + float rx, ry, rz; + // Translation parameter from one camera to another parameter + float tx, ty, tz; +}; + +struct imu_params { + // 3D vector to add to accelerometer readings + float linear_acceleration_bias[3]; + // 3D vector to add to gyroscope readings + float angular_velocity_bias[3]; + // gravity acceleration + float gravity_acceleration[3]; + // Extrinsic structure for IMU device + struct camera_extrinsics extr; + // Noise model parameters + float update_rate; + float linear_acceleration_noise_density; + float linear_acceleration_random_walk; + float angular_velocity_noise_density; + float angular_velocity_random_walk; +}; + +struct radial_lsc_params { + // Image height + u16 image_height; + // Image width + u16 image_width; + // Number of color channels + u8 n_channels; + // Coordinate x of center point + float rls_x0[MAX_RLS_COLOR_CHANNELS]; + // Coordinate y of center point + float rls_y0[MAX_RLS_COLOR_CHANNELS]; + // Ellipse xx parameter + double ekxx[MAX_RLS_COLOR_CHANNELS]; + // Ellipse xy parameter + double ekxy[MAX_RLS_COLOR_CHANNELS]; + // Ellipse yx parameter + double ekyx[MAX_RLS_COLOR_CHANNELS]; + // Ellipse yy parameter + double ekyy[MAX_RLS_COLOR_CHANNELS]; + // Number of breakpoints in LSC radial transfer function + u8 rls_n_points; + // LSC radial transfer function X + float rls_rad_tf_x[MAX_RLS_COLOR_CHANNELS][MAX_RLS_BREAKPOINTS]; + // LSC radial transfer function Y + float rls_rad_tf_y[MAX_RLS_COLOR_CHANNELS][MAX_RLS_BREAKPOINTS]; + // LSC radial transfer function slope + float rls_rad_tf_slope[MAX_RLS_COLOR_CHANNELS][MAX_RLS_BREAKPOINTS]; + // rScale parameter + u8 r_scale; +}; + +struct NvCamSyncSensorCalibData { + // Intrinsic structure for camera device + struct camera_intrinsics cam_intr; + + // Extrinsic structure for camera device + struct camera_extrinsics cam_extr; + + // Flag for IMU availability + u8 imu_present; + + // Intrinsic structure for IMU + struct imu_params imu; + + // HAWK module serial number + u8 serial_number[CAMERA_MAX_SN_LENGTH]; + + // Radial Lens Shading Correction parameters + struct radial_lsc_params rls; +}; + +struct LiEeprom_Content_Struct { + /** + * EEPROM layout version + */ + u32 version; + /** + * Factory Blob Flag, to set when factory flashed and reset to 0 + * when user modified + */ + u32 factory_data; + /** + * Intrinsic structure for camera device + */ + struct camera_intrinsics left_cam_intr; + struct camera_intrinsics right_cam_intr; + /** + * Extrinsic structure for camera device + */ + struct camera_extrinsics cam_extr; + /** + * Flag for IMU 0-absent, 1-present + */ + u8 imu_present; + /** + * Intrinsic structure for IMU + */ + struct imu_params imu; + + // HAWK module serial number + u8 serial_number[CAMERA_MAX_SN_LENGTH]; + + // Radial Lens Shading Correction parameters + struct radial_lsc_params left_rls; + struct radial_lsc_params right_rls; +}; + +struct ar0234 { + struct camera_common_eeprom_data eeprom[AR0234_EEPROM_NUM_BLOCKS]; + u8 eeprom_buf[AR0234_EEPROM_SIZE]; + struct i2c_client *i2c_client; + const struct i2c_device_id *id; + struct v4l2_subdev *subdev; + u32 frame_length; + struct camera_common_data *s_data; + struct tegracam_device *tc_dev; + u32 channel; + u32 sync_sensor_index; + struct NvCamSyncSensorCalibData EepromCalib; +}; + +static const struct regmap_config sensor_regmap_config = { + .reg_bits = 16, + .val_bits = 16, + .cache_type = REGCACHE_RBTREE, +}; + +static inline void ar0234_get_coarse_time_regs_shs1(ar0234_reg *regs, + u16 coarse_time) +{ + regs->addr = AR0234_COARSE_TIME_SHS1_ADDR; + regs->val = (coarse_time) & 0xffff; + +} + +static inline void ar0234_get_gain_reg(ar0234_reg *regs, + u16 gain) +{ + regs->addr = AR0234_ANALOG_GAIN; + regs->val = (gain) & 0xffff; + +} + +static int test_mode; +module_param(test_mode, int, 0644); + +static inline int ar0234_read_reg(struct camera_common_data *s_data, + u16 addr, u16 *val) +{ + int err = 0; + u32 reg_val = 0; + + err = regmap_read(s_data->regmap, addr, ®_val); + *val = reg_val & 0xFFFF; + + return err; +} + +static int ar0234_write_reg(struct camera_common_data *s_data, + u16 addr, u16 val) +{ + int err; + struct device *dev = s_data->dev; + + err = regmap_write(s_data->regmap, addr, val); + if (err) + dev_err(dev, "%s:i2c write failed, 0x%x = %x\n", + __func__, addr, val); + + return err; +} + +static int ar0234_hawk_link_check(struct ar0234 *priv) +{ + struct tegracam_device *tc_dev = priv->tc_dev; + struct device *dev = tc_dev->dev; + unsigned int linkA = 0; + unsigned int linkB = 0; + + dev_dbg(dev, "%s: channel %d, ", __func__, priv->channel); + + if (priv->channel == CHANNEL_N) + return 3; + + max96712_read_reg_Dser(0x52, priv->channel, 0x1A, &linkA); + max96712_read_reg_Dser(0x52, priv->channel, 0x0A, &linkB); + + dev_dbg(dev, "linA=%x, linB=%x\n", linkA, linkB); + if ((linkB & 0x8) && (linkA & 0x8)) + return 2; + else if (linkA & 0x8) + return 1; + else + return 0; +} + +static int ar0234_write_table(struct ar0234 *priv, + const struct index_reg_8 table[]) +{ + struct tegracam_device *tc_dev = priv->tc_dev; + struct device *dev = tc_dev->dev; + int i = 0; + int ret = 0; + int retry = 5; + + dev_dbg(dev, "%s: channel %d, ", __func__, priv->channel); + while (table[i].source != 0x00) { + if (table[i].source == 0x06) { + retry = 1; + + if (table[i].addr == AR0234_TABLE_WAIT_MS) { + dev_dbg(dev, "%s: sleep 500\n", __func__); + msleep(table[i].val); + i++; + continue; + } +retry_sensor: + ret = ar0234_write_reg(priv->s_data, table[i].addr, table[i].val); + if (ret) { + retry--; + if (retry > 0) { + dev_warn(dev, "ar0234_write_reg: try %d\n", retry); + msleep(4); + goto retry_sensor; + } + return -1; + } + + if (0x301a == table[i].addr || 0x3060 == table[i].addr) + msleep(100); + } else { + retry = 5; + + if (priv->channel == CHANNEL_N) { + i++; + continue; + } + +retry_serdes: + ret = max96712_write_reg_Dser(table[i].source, + priv->channel, table[i].addr, + (u8)table[i].val); + if (ret && (table[i].addr != 0x0000)) { + retry--; + if (retry > 0) { + dev_warn(dev, "max96712_write_reg_Dser: try %d\n", retry); + msleep(4); + goto retry_serdes; + } + return -1; + } + if (0x0010 == table[i].addr || 0x0000 == table[i].addr || + 0x0006 == table[i].addr || 0x0018 == table[i].addr) + msleep(300); + else + msleep(10); + } + i++; + } + return 0; +} + +static int ar0234_power_on(struct camera_common_data *s_data) +{ + int err = 0; + struct camera_common_power_rail *pw = s_data->power; + struct camera_common_pdata *pdata = s_data->pdata; + struct device *dev = s_data->dev; + + dev_dbg(dev, "%s: power on\n", __func__); + if (pdata && pdata->power_on) { + err = pdata->power_on(pw); + if (err) + dev_err(dev, "%s failed.\n", __func__); + else + pw->state = SWITCH_ON; + return err; + } + + if (pw->reset_gpio > 0) + gpio_set_value(pw->reset_gpio, 1); + + usleep_range(1000, 2000); + if (pw->reset_gpio > 0) + gpio_set_value(pw->reset_gpio, 1); + + usleep_range(10000, 20000); + pw->state = SWITCH_ON; + + return 0; +} + +static int ar0234_power_off(struct camera_common_data *s_data) +{ + int err = 0; + struct camera_common_power_rail *pw = s_data->power; + struct camera_common_pdata *pdata = s_data->pdata; + struct device *dev = s_data->dev; + + dev_dbg(dev, "%s:\n", __func__); + if (pdata && pdata->power_off) { + err = pdata->power_off(pw); + if (!err) + goto power_off_done; + else + dev_err(dev, "%s failed.\n", __func__); + return err; + } + +power_off_done: + pw->state = SWITCH_OFF; + + return 0; +} + +static int ar0234_power_get(struct tegracam_device *tc_dev) +{ + struct device *dev = tc_dev->dev; + struct camera_common_data *s_data = tc_dev->s_data; + struct camera_common_power_rail *pw = s_data->power; + struct camera_common_pdata *pdata = s_data->pdata; + const char *mclk_name; + const char *parentclk_name; + struct clk *parent; + int err = 0; + + mclk_name = pdata->mclk_name ? + pdata->mclk_name : "cam_mclk1"; + pw->mclk = devm_clk_get(dev, mclk_name); + if (IS_ERR(pw->mclk)) { + dev_err(dev, "unable to get clock %s\n", mclk_name); + return PTR_ERR(pw->mclk); + } + + parentclk_name = pdata->parentclk_name; + if (parentclk_name) { + parent = devm_clk_get(dev, parentclk_name); + if (IS_ERR(parent)) { + dev_err(dev, "unable to get parent clcok %s", + parentclk_name); + } else { + err = clk_set_parent(pw->mclk, parent); + if (err < 0) + dev_dbg(dev, + "%s failed to set parent clock %d\n", + __func__, err); + } + } + if (!err) { + pw->reset_gpio = pdata->reset_gpio; + pw->af_gpio = pdata->af_gpio; + pw->pwdn_gpio = pdata->pwdn_gpio; + } + + pw->state = SWITCH_OFF; + + return err; +} + +static int ar0234_power_put(struct tegracam_device *tc_dev) +{ + struct camera_common_data *s_data = tc_dev->s_data; + struct camera_common_power_rail *pw = s_data->power; + + if (unlikely(!pw)) + return -EFAULT; + + return 0; +} + +static int ar0234_set_group_hold(struct tegracam_device *tc_dev, bool val) +{ + struct device *dev = tc_dev->dev; + int err = 0; + + if (err) { + dev_dbg(dev, "%s: Group hold control error\n", __func__); + return err; + } + + return 0; +} + +static int ar0234_set_gain(struct tegracam_device *tc_dev, s64 val) +{ + struct camera_common_data *s_data = tc_dev->s_data; + struct device *dev = tc_dev->dev; + ar0234_reg reg_list[1]; + int err; + u16 gain = (u16)val; + u16 gain_reg = 0; + + if (val < 200) { + gain_reg = (32 * (1000 - (100000 / gain))) / 1000; + } else if (val < 400 && val >= 200) { + gain = gain / 2; + gain_reg = (16 * (1000 - (100000 / gain))) / 1000 * 2; + gain_reg = gain_reg + 0x10; + } else if (val < 800 && val >= 400) { + gain = gain / 4; + gain_reg = (32 * (1000 - (100000 / gain))) / 1000; + gain_reg = gain_reg + 0x20; + } else if (val < 1600 && val >= 800) { + gain = gain / 8; + gain_reg = (16 * (1000 - (100000 / gain))) / 1000 * 2; + gain_reg = gain_reg + 0x30; + } else if (val >= 1600) { + gain_reg = 0x40; + } + + if (gain > AR0234_MAX_GAIN_REG) + gain = AR0234_MAX_GAIN_REG; + ar0234_get_gain_reg(reg_list, gain_reg); + err = ar0234_write_reg(s_data, reg_list[0].addr, + reg_list[0].val); + if (err) + goto fail; + return 0; + +fail: + dev_info(dev, "%s: GAIN control error\n", __func__); + return err; +} + +static int ar0234_set_frame_rate(struct tegracam_device *tc_dev, s64 val) +{ + struct ar0234 *priv = (struct ar0234 *)tegracam_get_privdata(tc_dev); + + if (val == 30000000) { //30fps full resolution + max96712_write_reg_Dser(0x52, priv->channel, 0x04A5, 0x35); + max96712_write_reg_Dser(0x52, priv->channel, 0x04A6, 0xB7); + max96712_write_reg_Dser(0x52, priv->channel, 0x04A7, 0x0C); + priv->frame_length = 0xC20; + } else if (val == 60000000) {//60fps full resolution + max96712_write_reg_Dser(0x52, priv->channel, 0x04A5, 0x9A); + max96712_write_reg_Dser(0x52, priv->channel, 0x04A6, 0x5B); + max96712_write_reg_Dser(0x52, priv->channel, 0x04A7, 0x06); + priv->frame_length = 0x610; + } else if (val == 120000000) {//120fps binning resolution + max96712_write_reg_Dser(0x52, priv->channel, 0x04A5, 0xCD); + max96712_write_reg_Dser(0x52, priv->channel, 0x04A6, 0x2D); + max96712_write_reg_Dser(0x52, priv->channel, 0x04A7, 0x03); + priv->frame_length = 0x308; + } + + return 0; +} + +static int ar0234_set_exposure(struct tegracam_device *tc_dev, s64 val) +{ + struct ar0234 *priv = (struct ar0234 *)tegracam_get_privdata(tc_dev); + struct camera_common_data *s_data = tc_dev->s_data; + const struct sensor_mode_properties *mode = + &s_data->sensor_props.sensor_modes[s_data->mode]; + ar0234_reg reg_list[1]; + int err; + u32 coarse_time; + u32 shs1; + + if (priv->frame_length == 0) + priv->frame_length = AR0234_DEFAULT_FRAME_LENGTH; + + if (mode->image_properties.line_length == 0 || + mode->control_properties.exposure_factor == 0) + return -EINVAL; + + coarse_time = mode->signal_properties.pixel_clock.val * + val / mode->image_properties.line_length / + mode->control_properties.exposure_factor; + + if (coarse_time > priv->frame_length) + coarse_time = priv->frame_length; + shs1 = coarse_time; + /* 0 and 1 are prohibited */ + if (shs1 < 2) + shs1 = 2; + + ar0234_get_coarse_time_regs_shs1(reg_list, shs1); + err = ar0234_write_reg(priv->s_data, reg_list[0].addr, + reg_list[0].val); + if (err) + goto fail; + + return 0; + +fail: + dev_dbg(&priv->i2c_client->dev, + "%s: set coarse time error\n", __func__); + return err; +} + +static int ar0234_fill_string_ctrl(struct tegracam_device *tc_dev, + struct v4l2_ctrl *ctrl) +{ + struct ar0234 *priv = tc_dev->priv; + int i, ret; + + switch (ctrl->id) { + case TEGRA_CAMERA_CID_EEPROM_DATA: + for (i = 0; i < AR0234_EEPROM_SIZE; i++) { + ret = sprintf(&ctrl->p_new.p_char[i*2], "%02x", + priv->eeprom_buf[i]); + if (ret < 0) + return -EINVAL; + } + break; + default: + return -EINVAL; + } + ctrl->p_cur.p_char = ctrl->p_new.p_char; + + return 0; +} + +static int ar0234_fill_eeprom(struct tegracam_device *tc_dev, + struct v4l2_ctrl *ctrl) +{ + struct ar0234 *priv = tc_dev->priv; + struct LiEeprom_Content_Struct *tmp; + u32 test = 0; + + switch (ctrl->id) { + case TEGRA_CAMERA_CID_STEREO_EEPROM: + tmp = kmalloc(sizeof(struct LiEeprom_Content_Struct), + GFP_KERNEL); + if (tmp == NULL) + return -ENOMEM; + + memset(&(priv->EepromCalib), 0, + sizeof(struct NvCamSyncSensorCalibData)); + memset(ctrl->p_new.p, 0, + sizeof(struct NvCamSyncSensorCalibData)); + memcpy(tmp, priv->eeprom_buf, + sizeof(struct LiEeprom_Content_Struct)); + + if (priv->sync_sensor_index == 1) + priv->EepromCalib.cam_intr = tmp->left_cam_intr; + else if (priv->sync_sensor_index == 2) + priv->EepromCalib.cam_intr = tmp->right_cam_intr; + else + priv->EepromCalib.cam_intr = tmp->left_cam_intr; + + priv->EepromCalib.cam_extr = tmp->cam_extr; + priv->EepromCalib.imu_present = tmp->imu_present; + priv->EepromCalib.imu = tmp->imu; + memcpy(priv->EepromCalib.serial_number, tmp->serial_number, + CAMERA_MAX_SN_LENGTH); + + if (priv->sync_sensor_index == 1) + priv->EepromCalib.rls = tmp->left_rls; + else if (priv->sync_sensor_index == 2) + priv->EepromCalib.rls = tmp->right_rls; + else + priv->EepromCalib.rls = tmp->left_rls; + + memcpy(ctrl->p_new.p, (u8 *)&(priv->EepromCalib), + sizeof(struct NvCamSyncSensorCalibData)); + + kfree(tmp); + break; + default: + return -EINVAL; + } + + memcpy(&test, &(priv->EepromCalib.cam_intr.fx), 4); + + ctrl->p_cur.p = ctrl->p_new.p; + + return 0; +} + +static struct tegracam_ctrl_ops ar0234_ctrl_ops = { + .numctrls = ARRAY_SIZE(ctrl_cid_list), + .ctrl_cid_list = ctrl_cid_list, + .string_ctrl_size = {AR0234_EEPROM_STR_SIZE}, + .compound_ctrl_size = {sizeof(struct NvCamSyncSensorCalibData)}, + .set_gain = ar0234_set_gain, + .set_exposure = ar0234_set_exposure, + .set_exposure_short = ar0234_set_exposure, + .set_frame_rate = ar0234_set_frame_rate, + .set_group_hold = ar0234_set_group_hold, + .fill_string_ctrl = ar0234_fill_string_ctrl, + .fill_compound_ctrl = ar0234_fill_eeprom, +}; + +static struct camera_common_pdata *ar0234_parse_dt(struct tegracam_device *tc_dev) +{ + struct device *dev = tc_dev->dev; + struct device_node *node = dev->of_node; + struct camera_common_pdata *board_priv_pdata; + const struct of_device_id *match; + int err; + int gpio = 0; + + if (!node) + return NULL; + + match = of_match_device(ar0234_of_match, dev); + if (!match) { + dev_err(dev, "Failed to find matching dt id\n"); + return NULL; + } + + board_priv_pdata = devm_kzalloc(dev, sizeof(*board_priv_pdata), GFP_KERNEL); + + err = of_property_read_string(node, "mclk", + &board_priv_pdata->mclk_name); + if (err) + dev_err(dev, "mclk not in DT\n"); + + board_priv_pdata->reset_gpio = of_get_named_gpio(node, + "reset-gpios", 0); + gpio_direction_output(board_priv_pdata->reset_gpio, 1); + + gpio = of_get_named_gpio(node, + "pwdn-gpios", 0); + + gpio_direction_output(gpio, 1); + gpio = of_get_named_gpio(node, + "pwr-gpios", 0); + + gpio_direction_output(gpio, 1); + + board_priv_pdata->has_eeprom = + of_property_read_bool(node, "has-eeprom"); + return board_priv_pdata; +} + +static int ar0234_set_mode(struct tegracam_device *tc_dev) +{ + struct ar0234 *priv = (struct ar0234 *)tegracam_get_privdata(tc_dev); + struct camera_common_data *s_data = tc_dev->s_data; + struct device *dev = tc_dev->dev; + const struct of_device_id *match; + int err; + + match = of_match_device(ar0234_of_match, dev); + if (!match) { + dev_err(dev, "Failed to find matching dt id\n"); + return -EINVAL; + } + + err = ar0234_write_table(priv, mode_table[AR0234_MODE_STOP_STREAM]); + if (err) + return err; + + if (s_data->mode_prop_idx < 0) + return -EINVAL; + dev_dbg(dev, "%s: mode index:%d\n", __func__, s_data->mode_prop_idx); + err = ar0234_write_table(priv, mode_table[s_data->mode_prop_idx]); + if (err) + return err; + + return 0; +} + +static int ar0234_start_streaming(struct tegracam_device *tc_dev) +{ + struct ar0234 *priv = (struct ar0234 *)tegracam_get_privdata(tc_dev); + int err; + + if (test_mode) { + err = ar0234_write_table(priv, + mode_table[AR0234_MODE_TEST_PATTERN]); + if (err) + return err; + } + + + err = ar0234_write_table(priv, + mode_table[AR0234_MODE_START_STREAM]); + if (err) + return err; + + return 0; + +} + +static int ar0234_stop_streaming(struct tegracam_device *tc_dev) +{ + struct ar0234 *priv = (struct ar0234 *)tegracam_get_privdata(tc_dev); + int err; + + err = ar0234_write_table(priv, mode_table[AR0234_MODE_STOP_STREAM]); + if (err) + return err; + + return 0; +} + +static struct camera_common_sensor_ops ar0234_common_ops = { + .numfrmfmts = ARRAY_SIZE(ar0234_frmfmt), + .frmfmt_table = ar0234_frmfmt, + .power_on = ar0234_power_on, + .power_off = ar0234_power_off, + .parse_dt = ar0234_parse_dt, + .power_get = ar0234_power_get, + .power_put = ar0234_power_put, + .set_mode = ar0234_set_mode, + .start_streaming = ar0234_start_streaming, + .stop_streaming = ar0234_stop_streaming, +}; + +static int ar0234_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + dev_dbg(&client->dev, "%s:\n", __func__); + + return 0; +} + +static int ar0234_eeprom_device_release(struct ar0234 *priv) +{ + int i; + + for (i = 0; i < AR0234_EEPROM_NUM_BLOCKS; i++) { + if (priv->eeprom[i].i2c_client != NULL) { + i2c_unregister_device(priv->eeprom[i].i2c_client); + priv->eeprom[i].i2c_client = NULL; + } + } + + return 0; +} + +static const struct v4l2_subdev_internal_ops ar0234_subdev_internal_ops = { + .open = ar0234_open, +}; + + +static int ar0234_eeprom_device_init(struct ar0234 *priv) +{ + struct camera_common_pdata *pdata = priv->s_data->pdata; + char *dev_name = "eeprom_ar0234"; + static struct regmap_config eeprom_regmap_config = { + .reg_bits = 8, + .val_bits = 8 + }; + int i; + int err; + + if (!pdata->has_eeprom) + return -EINVAL; + + for (i = 0; i < AR0234_EEPROM_NUM_BLOCKS; i++) { + priv->eeprom[i].adap = i2c_get_adapter( + priv->i2c_client->adapter->nr); + memset(&priv->eeprom[i].brd, 0, sizeof(priv->eeprom[i].brd)); + strncpy(priv->eeprom[i].brd.type, dev_name, + sizeof(priv->eeprom[i].brd.type)); + + if (priv->sync_sensor_index == 1) + priv->eeprom[i].brd.addr = AR0234_EEPROM_ADDRESS + i; + else if (priv->sync_sensor_index == 2) + priv->eeprom[i].brd.addr = AR0234_EEPROM_ADDRESS_R + i; + + priv->eeprom[i].i2c_client = i2c_new_client_device( + priv->eeprom[i].adap, &priv->eeprom[i].brd); + priv->eeprom[i].regmap = devm_regmap_init_i2c( + priv->eeprom[i].i2c_client, &eeprom_regmap_config); + if (IS_ERR(priv->eeprom[i].regmap)) { + err = PTR_ERR(priv->eeprom[i].regmap); + ar0234_eeprom_device_release(priv); + return err; + } + } + + return 0; +} + +static int ar0234_read_eeprom(struct ar0234 *priv) +{ + int err, i; + + for (i = 0; i < AR0234_EEPROM_NUM_BLOCKS; i++) { + err = regmap_bulk_read(priv->eeprom[i].regmap, 0, + &priv->eeprom_buf[i * AR0234_EEPROM_BLOCK_SIZE], + AR0234_EEPROM_BLOCK_SIZE); + if (err) + return err; + } + + return 0; +} + +static int ar0234_board_setup(struct ar0234 *priv) +{ + struct camera_common_data *s_data = priv->s_data; + struct device *dev = s_data->dev; + bool eeprom_ctrl = 0; + int err = 0; + + dev_dbg(dev, "%s++\n", __func__); + + /* eeprom interface */ + err = ar0234_eeprom_device_init(priv); + if (err && s_data->pdata->has_eeprom) + dev_err(dev, "Failed to allocate eeprom reg map: %d\n", err); + eeprom_ctrl = !err; + + err = camera_common_mclk_enable(s_data); + if (err) { + dev_err(dev, "Error %d turning on mclk\n", err); + return err; + } + + err = ar0234_power_on(s_data); + if (err) { + dev_err(dev, "Error %d during power on sensor\n", err); + return err; + } + + if (eeprom_ctrl) { + err = ar0234_read_eeprom(priv); + if (err) + dev_err(dev, "Error %d reading eeprom\n", err); + } + + ar0234_power_off(s_data); + camera_common_mclk_disable(s_data); + return err; +} + + + +static int ar0234_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct device_node *node = dev->of_node; + struct tegracam_device *tc_dev; + struct ar0234 *priv; + const char *str; + int err; + + dev_info(dev, "probing v4l2 sensor.\n"); + + if (!IS_ENABLED(CONFIG_OF) || !node) + return -EINVAL; + + priv = devm_kzalloc(dev, sizeof(struct ar0234), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + tc_dev = devm_kzalloc(dev, + sizeof(struct tegracam_device), GFP_KERNEL); + if (!tc_dev) + return -ENOMEM; + + err = of_property_read_string(node, "channel", &str); + if (err) + dev_err(dev, "channel not found\n"); + priv->channel = str[0] - 'a'; + dev_dbg(dev, "%s: channel %d\n", __func__, priv->channel); + + + err = of_property_read_u32(node, "sync_sensor_index", + &priv->sync_sensor_index); + if (err) + dev_err(dev, "sync name index not in DT\n"); + + priv->i2c_client = tc_dev->client = client; + tc_dev->dev = dev; + strncpy(tc_dev->name, "ar0234", sizeof(tc_dev->name)); + tc_dev->dev_regmap_config = &sensor_regmap_config; + tc_dev->sensor_ops = &ar0234_common_ops; + tc_dev->v4l2sd_internal_ops = &ar0234_subdev_internal_ops; + tc_dev->tcctrl_ops = &ar0234_ctrl_ops; + + err = tegracam_device_register(tc_dev); + if (err) { + dev_err(dev, "tegra camera driver registration failed\n"); + return err; + } + priv->tc_dev = tc_dev; + priv->s_data = tc_dev->s_data; + priv->subdev = &tc_dev->s_data->subdev; + tegracam_set_privdata(tc_dev, (void *)priv); + + ar0234_power_on(tc_dev->s_data); + msleep(100); + + if (ar0234_hawk_link_check(priv) == 2) { + err = ar0234_write_table(priv, mode_table[AR0234_MODE_Dser_Ser]); + if (err) { + dev_info(&client->dev, "dual camera detect error\n"); + return err; + } + dev_info(&client->dev, "dual camera detect success\n"); + } else if (ar0234_hawk_link_check(priv) == 1) { + err = ar0234_write_table(priv, mode_table[AR0234_MODE_Single_Dser_Ser]); + if (err) { + dev_info(&client->dev, "single detect error\n"); + return err; + } + dev_info(&client->dev, "single detect success\n"); + } else if (ar0234_hawk_link_check(priv) == 3) { + ; + } else { + return -1; + } + + err = ar0234_write_table(priv, mode_table[AR0234_MODE_STOP_STREAM]); + if (err) { + dev_info(&client->dev, "ar0234 detect error\n"); + return err; + } + + msleep(100); + err = ar0234_board_setup(priv); + if (err) { + dev_err(dev, "board setup failed\n"); + return err; + } + + err = tegracam_v4l2subdev_register(tc_dev, true); + if (err) { + dev_err(dev, "tegra camera subdev registration failed\n"); + return err; + } + + dev_info(&client->dev, "Detected AR0234 sensor\n"); + + return 0; +} + +#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE) +static int ar0234_remove(struct i2c_client *client) +#else +static void ar0234_remove(struct i2c_client *client) +#endif +{ + struct camera_common_data *s_data = to_camera_common_data(&client->dev); + struct ar0234 *priv; + + if (!s_data) +#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE) + return -EINVAL; +#else + return; +#endif + + priv = (struct ar0234 *)s_data->priv; + tegracam_v4l2subdev_unregister(priv->tc_dev); + tegracam_device_unregister(priv->tc_dev); + ar0234_eeprom_device_release(priv); +#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE) + return 0; +#endif +} + +static const struct i2c_device_id ar0234_id[] = { + { "ar0234", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, ar0234_id); + +static struct i2c_driver ar0234_i2c_driver = { + .driver = { + .name = "ar0234", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ar0234_of_match), + }, + .probe = ar0234_probe, + .remove = ar0234_remove, + .id_table = ar0234_id, +}; + +module_i2c_driver(ar0234_i2c_driver); + +MODULE_DESCRIPTION("Media Controller driver for Sony AR0234"); +MODULE_AUTHOR("NVIDIA Corporation"); +MODULE_AUTHOR("Sudhir Vyas GMSL API: Gigabit Multimedia Serial Link protocol + * + * @b Description: Defines elements used to set up and use a GMSL link. + */ + +#ifndef __GMSL_LINK_H__ +/** + * \defgroup GMSL Gigabit Multimedia Serial Link (GMSL) + * + * Defines the interface used to control the MAX9295 serializer and + * MAX9296 deserializer modules. + * + * @ingroup serdes_group + * @{ + */ + +#define __GMSL_LINK_H__ + +#define GMSL_CSI_1X4_MODE 0x1 +#define GMSL_CSI_2X4_MODE 0x2 +#define GMSL_CSI_2X2_MODE 0x3 +#define GMSL_CSI_4X2_MODE 0x4 + +#define GMSL_CSI_PORT_A 0x0 +#define GMSL_CSI_PORT_B 0x1 +#define GMSL_CSI_PORT_C 0x2 +#define GMSL_CSI_PORT_D 0x3 +#define GMSL_CSI_PORT_E 0x4 +#define GMSL_CSI_PORT_F 0x5 + +#define GMSL_SERDES_CSI_LINK_A 0x1 +#define GMSL_SERDES_CSI_LINK_B 0x2 + +/* Didn't find kernel defintions, for now adding here */ +#define GMSL_CSI_DT_RAW_12 0x2C +#define GMSL_CSI_DT_UED_U1 0x30 +#define GMSL_CSI_DT_EMBED 0x12 + +#define GMSL_ST_ID_UNUSED 0xFF + +/** + * Maximum number of data streams (\ref gmsl_stream elements) in a GMSL link + * (\ref gmsl_link_ctx). + */ +#define GMSL_DEV_MAX_NUM_DATA_STREAMS 4 + +/** + * Holds information about a data stream in a GMSL link (\ref gmsl_link_ctx). + */ +struct gmsl_stream { + __u32 st_id_sel; + __u32 st_data_type; + __u32 des_pipe; +}; + +/** + * Holds the configuration of the GMSL links from a sensor to its serializer to + * its deserializer. + */ +struct gmsl_link_ctx { + /**< Default sensor virtual channel. */ + __u32 st_vc; + /**< Destination virtual channel (user-defined). */ + __u32 dst_vc; + /**< Sensor to serializer CSI port connection. */ + __u32 src_csi_port; + /**< Deserializer to Jetson CSI port connection. */ + __u32 dst_csi_port; + /**< GMSL link between serializer and deserializer devices. */ + __u32 serdes_csi_link; + /**< Number of active streams to be mapped from sensor. */ + __u32 num_streams; + /**< Sensor's CSI lane configuration. */ + __u32 num_csi_lanes; + /**< Deserializer CSI mode. */ + __u32 csi_mode; + /**< Serializer slave address. */ + __u32 ser_reg; + /**< Sensor proxy slave address. */ + __u32 sdev_reg; + /**< Sensor default slave address. */ + __u32 sdev_def; + /**< Indicates whether the serializer device for + * the specified sensor source was found. Set by + * the serializer driver during setup; used by + * the deserializer driver to choose certain + * configuration settings during setup. + */ + bool serdev_found; + /*< An array of information about the data streams in the link. */ + struct gmsl_stream streams[GMSL_DEV_MAX_NUM_DATA_STREAMS]; + /**< Sensor device handle. */ + struct device *s_dev; +}; + +/** @} */ + +#endif /* __GMSL_LINK_H__ */ diff --git a/include/media/max9295.h b/include/media/max9295.h new file mode 100644 index 00000000..bf801aa2 --- /dev/null +++ b/include/media/max9295.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ + +/** + * @file + * MAX9295 API: For Maxim Integrated MAX9295 serializer + * + * @b Description: Defines elements used to set up and use a + * Maxim Integrated MAX9295 serializer. + */ + +#ifndef __MAX9295_H__ +#define __MAX9295_H__ + +#include +/** + * \defgroup max9295 MAX9295 serializer driver + * + * Controls the MAX9295 serializer module. + * + * @ingroup serdes_group + * @{ + */ + + +/** + * @brief Powers on a serializer device and performs the I2C overrides + * for sensor and serializer devices. + * + * The I2C overrides include setting proxy I2C slave addresses for the devices. + * + * Before the client calls this function it must ensure that + * the deserializer device is in link_ex exclusive link mode + * by calling the deserializer driver's max9296_setup_link() function. + * + * @param [in] dev The serializer device handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9295_setup_control(struct device *dev); + +/** + * Reverts I2C overrides and resets a serializer device. + * + * @param [in] dev The serializer device handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9295_reset_control(struct device *dev); + +/** + * @brief Pairs a sensor device with a serializer device. + * + * To be called by sensor client driver. + * + * @param [in] dev The deserializer device handle. + * @param [in] g_ctx The @ref gmsl_link_ctx structure handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9295_sdev_pair(struct device *dev, struct gmsl_link_ctx *g_ctx); + +/** + * @brief Unpairs a sensor device from a serializer device. + * + * To be called by sensor client driver. + * + * @param [in] dev The serializer device handle. + * @param [in] s_dev The sensor device handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9295_sdev_unpair(struct device *dev, struct device *s_dev); + +/** + * Sets up the serializer device's internal pipeline for a specified + * sensor/serializer pair. + * + * @param [in] dev The serializer device handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9295_setup_streaming(struct device *dev); + +/** @} */ + +#endif /* __MAX9295_H__ */ diff --git a/include/media/max9296.h b/include/media/max9296.h new file mode 100644 index 00000000..210dbc80 --- /dev/null +++ b/include/media/max9296.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ + +/** + * @file + * MAX9296 API: For Maxim Integrated MAX9296 deserializer + * + * @b Description: Defines elements used to set up and use a + * Maxim Integrated MAX9296 deserializer. + */ + +#ifndef __MAX9296_H__ +#define __MAX9296_H__ + +#include +/** + * \defgroup max9296 MAX9296 deserializer driver + * + * Controls the MAX9296 deserializer module. + * + * @ingroup serdes_group + * @{ + */ + +/** + * Puts a deserializer device in single exclusive link mode, so link-specific + * I2C overrides can be performed for sensor and serializer devices. + * + * @param [in] dev The deserializer device handle. + * @param [in] s_dev The sensor device handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9296_setup_link(struct device *dev, struct device *s_dev); + +/** + * @brief Sets up a deserializer link's control pipeline. + * + * Puts the deserializer in dual splitter mode. You must call this function + * during device boot, after max9296_setup_link(). + * + * @param [in] dev The deserializer device handle. + * @param [in] s_dev The sensor device handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9296_setup_control(struct device *dev, struct device *s_dev); + +/** + * @brief Resets a deserializer device's link control pipeline. + * + * The deserializer driver internally decrements the reference count and + * resets the deserializer device if all the source sensor devices are + * powered off, resetting all control and streaming configuration. + * + * @param [in] dev The deserializer device handle. + * @param [in] s_dev The sensor device handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9296_reset_control(struct device *dev, struct device *s_dev); + +/** + * @brief Registers a source sensor device with a deserializer device. + * + * The deserializer driver internally checks all perquisites and compatibility + * factors. If it finds that the registration request is valid, + * it stores the source's @ref gmsl_link_ctx context handle in the source list + * maintained by the deserializer driver instance. + * + * @param [in] dev The deserializer device handle. + * @param [in] g_ctx A @c gmsl_link_ctx structure handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9296_sdev_register(struct device *dev, struct gmsl_link_ctx *g_ctx); + +/** + * Unregisters a source sensor device from its deserializer device. + * + * @param [in] dev The deserializer device handle. + * @param [in] s_dev The sensor device handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9296_sdev_unregister(struct device *dev, struct device *s_dev); + +/** + * Performs internal pipeline configuration for a link in context to set up + * streaming, and puts the deserializer link in ready-to-stream state. + * + * @param [in] dev The deserializer device handle. + * @param [in] s_dev The sensor device handle. + * + * @return 0 or success, or -1 otherwise. + */ +int max9296_setup_streaming(struct device *dev, struct device *s_dev); + +/** + * @brief Enables streaming. + * + * This function is to be called by the sensor client driver. + * + * @param [in] dev The deserializer device handle. + * @param [in] s_dev The sensor device handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9296_start_streaming(struct device *dev, struct device *s_dev); + +/** + * @brief Disables streaming. + * + * This function is to be called by the sensor client driver. + * + * @note Both @c max9296_start_streaming and @c max9296_stop_streaming + * are mainly added to enable and disable sensor streaming on the fly + * while other sensors are active. + * + * @param [in] dev The deserializer device handle. + * @param [in] s_dev The sensor device handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9296_stop_streaming(struct device *dev, struct device *s_dev); + +/** + * @brief Powers on the max9296 deserializer module. + * + * Asserts shared reset GPIO and powers on the regulator; + * maintains the reference count internally for source devices. + * + * @param [in] dev The deserializer device handle. + * + * @return 0 for success, or -1 otherwise. + */ +int max9296_power_on(struct device *dev); + +/** + * @brief Powers off the max9296 deserializer module. + * + * Deasserts the shared reset GPIO and powers off the regulator based on + * the reference count. + * + * @param [in] dev The deserializer device handle. + */ +void max9296_power_off(struct device *dev); + +/** @} */ + +#endif /* __MAX9296_H__ */