Jacopo Mondi | 34009bf | 2020-06-12 16:47:13 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * IMI RDACM20 GMSL Camera Driver |
| 4 | * |
| 5 | * Copyright (C) 2017-2020 Jacopo Mondi |
| 6 | * Copyright (C) 2017-2020 Kieran Bingham |
| 7 | * Copyright (C) 2017-2019 Laurent Pinchart |
| 8 | * Copyright (C) 2017-2019 Niklas Söderlund |
| 9 | * Copyright (C) 2016 Renesas Electronics Corporation |
| 10 | * Copyright (C) 2015 Cogent Embedded, Inc. |
| 11 | */ |
| 12 | |
| 13 | /* |
| 14 | * The camera is made of an Omnivision OV10635 sensor connected to a Maxim |
| 15 | * MAX9271 GMSL serializer. |
| 16 | */ |
| 17 | |
| 18 | #include <linux/delay.h> |
| 19 | #include <linux/fwnode.h> |
| 20 | #include <linux/init.h> |
| 21 | #include <linux/i2c.h> |
| 22 | #include <linux/module.h> |
| 23 | #include <linux/slab.h> |
| 24 | #include <linux/videodev2.h> |
| 25 | |
| 26 | #include <media/v4l2-async.h> |
| 27 | #include <media/v4l2-ctrls.h> |
| 28 | #include <media/v4l2-subdev.h> |
| 29 | |
| 30 | #include "max9271.h" |
| 31 | |
| 32 | #define OV10635_I2C_ADDRESS 0x30 |
| 33 | |
| 34 | #define OV10635_SOFTWARE_RESET 0x0103 |
| 35 | #define OV10635_PID 0x300a |
| 36 | #define OV10635_VER 0x300b |
| 37 | #define OV10635_SC_CMMN_SCCB_ID 0x300c |
| 38 | #define OV10635_SC_CMMN_SCCB_ID_SELECT BIT(0) |
| 39 | #define OV10635_VERSION 0xa635 |
| 40 | |
| 41 | #define OV10635_WIDTH 1280 |
| 42 | #define OV10635_HEIGHT 800 |
| 43 | |
| 44 | /* VTS = PCLK / FPS / HTS / 2 (= 88MHz / 1572 / 30 / 2) */ |
| 45 | #define OV10635_HTS 1572 |
| 46 | /* FPS = 29,9998 */ |
| 47 | #define OV10635_VTS 933 |
| 48 | |
| 49 | /* |
| 50 | * As the drivers supports a single MEDIA_BUS_FMT_UYVY8_2X8 format we |
| 51 | * can harcode the pixel rate. |
| 52 | * |
| 53 | * PCLK is fed through the system clock, programmed @88MHz. |
| 54 | * MEDIA_BUS_FMT_UYVY8_2X8 format = 2 samples per pixel. |
| 55 | * |
| 56 | * Pixelrate = PCLK / 2 |
| 57 | * FPS = (OV10635_VTS * OV10635_HTS) / PixelRate |
| 58 | * = 29,9998 |
| 59 | */ |
| 60 | #define OV10635_PIXEL_RATE (44000000) |
| 61 | |
| 62 | static const struct ov10635_reg { |
| 63 | u16 reg; |
| 64 | u8 val; |
| 65 | } ov10635_regs_wizard[] = { |
| 66 | { 0x301b, 0xff }, { 0x301c, 0xff }, { 0x301a, 0xff }, { 0x3011, 0x42 }, |
| 67 | { 0x6900, 0x0c }, { 0x6901, 0x19 }, { 0x3503, 0x10 }, { 0x3025, 0x03 }, |
| 68 | { 0x3003, 0x16 }, { 0x3004, 0x30 }, { 0x3005, 0x40 }, { 0x3006, 0x91 }, |
| 69 | { 0x3600, 0x74 }, { 0x3601, 0x2b }, { 0x3612, 0x00 }, { 0x3611, 0x67 }, |
| 70 | { 0x3633, 0xca }, { 0x3602, 0xaf }, { 0x3603, 0x04 }, { 0x3630, 0x28 }, |
| 71 | { 0x3631, 0x16 }, { 0x3714, 0x10 }, { 0x371d, 0x01 }, { 0x4300, 0x3a }, |
| 72 | { 0x3007, 0x01 }, { 0x3024, 0x03 }, { 0x3020, 0x0a }, { 0x3702, 0x0d }, |
| 73 | { 0x3703, 0x20 }, { 0x3704, 0x15 }, { 0x3709, 0xa8 }, { 0x370c, 0xc7 }, |
| 74 | { 0x370d, 0x80 }, { 0x3712, 0x00 }, { 0x3713, 0x20 }, { 0x3715, 0x04 }, |
| 75 | { 0x381d, 0x40 }, { 0x381c, 0x00 }, { 0x3822, 0x50 }, { 0x3824, 0x10 }, |
| 76 | { 0x3815, 0x8c }, { 0x3804, 0x05 }, { 0x3805, 0x1f }, { 0x3800, 0x00 }, |
| 77 | { 0x3801, 0x00 }, { 0x3806, 0x03 }, { 0x3807, 0x28 }, { 0x3802, 0x00 }, |
| 78 | { 0x3803, 0x07 }, { 0x3808, 0x05 }, { 0x3809, 0x00 }, { 0x380a, 0x03 }, |
| 79 | { 0x380b, 0x20 }, { 0x380c, OV10635_HTS >> 8 }, |
| 80 | { 0x380d, OV10635_HTS & 0xff }, { 0x380e, OV10635_VTS >> 8 }, |
| 81 | { 0x380f, OV10635_VTS & 0xff }, { 0x3813, 0x02 }, { 0x3811, 0x08 }, |
| 82 | { 0x381f, 0x0c }, { 0x3819, 0x04 }, { 0x3804, 0x01 }, { 0x3805, 0x00 }, |
| 83 | { 0x3828, 0x03 }, { 0x3829, 0x10 }, { 0x382a, 0x10 }, { 0x3621, 0x63 }, |
| 84 | { 0x5005, 0x08 }, { 0x56d5, 0x00 }, { 0x56d6, 0x80 }, { 0x56d7, 0x00 }, |
| 85 | { 0x56d8, 0x00 }, { 0x56d9, 0x00 }, { 0x56da, 0x80 }, { 0x56db, 0x00 }, |
| 86 | { 0x56dc, 0x00 }, { 0x56e8, 0x00 }, { 0x56e9, 0x7f }, { 0x56ea, 0x00 }, |
| 87 | { 0x56eb, 0x7f }, { 0x5100, 0x00 }, { 0x5101, 0x80 }, { 0x5102, 0x00 }, |
| 88 | { 0x5103, 0x80 }, { 0x5104, 0x00 }, { 0x5105, 0x80 }, { 0x5106, 0x00 }, |
| 89 | { 0x5107, 0x80 }, { 0x5108, 0x00 }, { 0x5109, 0x00 }, { 0x510a, 0x00 }, |
| 90 | { 0x510b, 0x00 }, { 0x510c, 0x00 }, { 0x510d, 0x00 }, { 0x510e, 0x00 }, |
| 91 | { 0x510f, 0x00 }, { 0x5110, 0x00 }, { 0x5111, 0x80 }, { 0x5112, 0x00 }, |
| 92 | { 0x5113, 0x80 }, { 0x5114, 0x00 }, { 0x5115, 0x80 }, { 0x5116, 0x00 }, |
| 93 | { 0x5117, 0x80 }, { 0x5118, 0x00 }, { 0x5119, 0x00 }, { 0x511a, 0x00 }, |
| 94 | { 0x511b, 0x00 }, { 0x511c, 0x00 }, { 0x511d, 0x00 }, { 0x511e, 0x00 }, |
| 95 | { 0x511f, 0x00 }, { 0x56d0, 0x00 }, { 0x5006, 0x04 }, { 0x5608, 0x05 }, |
| 96 | { 0x52d7, 0x06 }, { 0x528d, 0x08 }, { 0x5293, 0x12 }, { 0x52d3, 0x12 }, |
| 97 | { 0x5288, 0x06 }, { 0x5289, 0x20 }, { 0x52c8, 0x06 }, { 0x52c9, 0x20 }, |
| 98 | { 0x52cd, 0x04 }, { 0x5381, 0x00 }, { 0x5382, 0xff }, { 0x5589, 0x76 }, |
| 99 | { 0x558a, 0x47 }, { 0x558b, 0xef }, { 0x558c, 0xc9 }, { 0x558d, 0x49 }, |
| 100 | { 0x558e, 0x30 }, { 0x558f, 0x67 }, { 0x5590, 0x3f }, { 0x5591, 0xf0 }, |
| 101 | { 0x5592, 0x10 }, { 0x55a2, 0x6d }, { 0x55a3, 0x55 }, { 0x55a4, 0xc3 }, |
| 102 | { 0x55a5, 0xb5 }, { 0x55a6, 0x43 }, { 0x55a7, 0x38 }, { 0x55a8, 0x5f }, |
| 103 | { 0x55a9, 0x4b }, { 0x55aa, 0xf0 }, { 0x55ab, 0x10 }, { 0x5581, 0x52 }, |
| 104 | { 0x5300, 0x01 }, { 0x5301, 0x00 }, { 0x5302, 0x00 }, { 0x5303, 0x0e }, |
| 105 | { 0x5304, 0x00 }, { 0x5305, 0x0e }, { 0x5306, 0x00 }, { 0x5307, 0x36 }, |
| 106 | { 0x5308, 0x00 }, { 0x5309, 0xd9 }, { 0x530a, 0x00 }, { 0x530b, 0x0f }, |
| 107 | { 0x530c, 0x00 }, { 0x530d, 0x2c }, { 0x530e, 0x00 }, { 0x530f, 0x59 }, |
| 108 | { 0x5310, 0x00 }, { 0x5311, 0x7b }, { 0x5312, 0x00 }, { 0x5313, 0x22 }, |
| 109 | { 0x5314, 0x00 }, { 0x5315, 0xd5 }, { 0x5316, 0x00 }, { 0x5317, 0x13 }, |
| 110 | { 0x5318, 0x00 }, { 0x5319, 0x18 }, { 0x531a, 0x00 }, { 0x531b, 0x26 }, |
| 111 | { 0x531c, 0x00 }, { 0x531d, 0xdc }, { 0x531e, 0x00 }, { 0x531f, 0x02 }, |
| 112 | { 0x5320, 0x00 }, { 0x5321, 0x24 }, { 0x5322, 0x00 }, { 0x5323, 0x56 }, |
| 113 | { 0x5324, 0x00 }, { 0x5325, 0x85 }, { 0x5326, 0x00 }, { 0x5327, 0x20 }, |
| 114 | { 0x5609, 0x01 }, { 0x560a, 0x40 }, { 0x560b, 0x01 }, { 0x560c, 0x40 }, |
| 115 | { 0x560d, 0x00 }, { 0x560e, 0xfa }, { 0x560f, 0x00 }, { 0x5610, 0xfa }, |
| 116 | { 0x5611, 0x02 }, { 0x5612, 0x80 }, { 0x5613, 0x02 }, { 0x5614, 0x80 }, |
| 117 | { 0x5615, 0x01 }, { 0x5616, 0x2c }, { 0x5617, 0x01 }, { 0x5618, 0x2c }, |
| 118 | { 0x563b, 0x01 }, { 0x563c, 0x01 }, { 0x563d, 0x01 }, { 0x563e, 0x01 }, |
| 119 | { 0x563f, 0x03 }, { 0x5640, 0x03 }, { 0x5641, 0x03 }, { 0x5642, 0x05 }, |
| 120 | { 0x5643, 0x09 }, { 0x5644, 0x05 }, { 0x5645, 0x05 }, { 0x5646, 0x05 }, |
| 121 | { 0x5647, 0x05 }, { 0x5651, 0x00 }, { 0x5652, 0x80 }, { 0x521a, 0x01 }, |
| 122 | { 0x521b, 0x03 }, { 0x521c, 0x06 }, { 0x521d, 0x0a }, { 0x521e, 0x0e }, |
| 123 | { 0x521f, 0x12 }, { 0x5220, 0x16 }, { 0x5223, 0x02 }, { 0x5225, 0x04 }, |
| 124 | { 0x5227, 0x08 }, { 0x5229, 0x0c }, { 0x522b, 0x12 }, { 0x522d, 0x18 }, |
| 125 | { 0x522f, 0x1e }, { 0x5241, 0x04 }, { 0x5242, 0x01 }, { 0x5243, 0x03 }, |
| 126 | { 0x5244, 0x06 }, { 0x5245, 0x0a }, { 0x5246, 0x0e }, { 0x5247, 0x12 }, |
| 127 | { 0x5248, 0x16 }, { 0x524a, 0x03 }, { 0x524c, 0x04 }, { 0x524e, 0x08 }, |
| 128 | { 0x5250, 0x0c }, { 0x5252, 0x12 }, { 0x5254, 0x18 }, { 0x5256, 0x1e }, |
| 129 | /* fifo_line_length = 2*hts */ |
| 130 | { 0x4606, (2 * OV10635_HTS) >> 8 }, { 0x4607, (2 * OV10635_HTS) & 0xff }, |
| 131 | /* fifo_hsync_start = 2*(hts - xres) */ |
| 132 | { 0x460a, (2 * (OV10635_HTS - OV10635_WIDTH)) >> 8 }, |
| 133 | { 0x460b, (2 * (OV10635_HTS - OV10635_WIDTH)) & 0xff }, |
| 134 | { 0x460c, 0x00 }, { 0x4620, 0x0e }, |
| 135 | /* BT601: 0x08 is also acceptable as HS/VS mode */ |
| 136 | { 0x4700, 0x04 }, { 0x4701, 0x00 }, { 0x4702, 0x01 }, { 0x4004, 0x04 }, |
| 137 | { 0x4005, 0x18 }, { 0x4001, 0x06 }, { 0x4050, 0x22 }, { 0x4051, 0x24 }, |
| 138 | { 0x4052, 0x02 }, { 0x4057, 0x9c }, { 0x405a, 0x00 }, { 0x4202, 0x02 }, |
| 139 | { 0x3023, 0x10 }, { 0x0100, 0x01 }, { 0x0100, 0x01 }, { 0x6f10, 0x07 }, |
| 140 | { 0x6f11, 0x82 }, { 0x6f12, 0x04 }, { 0x6f13, 0x00 }, { 0xd000, 0x19 }, |
| 141 | { 0xd001, 0xa0 }, { 0xd002, 0x00 }, { 0xd003, 0x01 }, { 0xd004, 0xa9 }, |
| 142 | { 0xd005, 0xad }, { 0xd006, 0x10 }, { 0xd007, 0x40 }, { 0xd008, 0x44 }, |
| 143 | { 0xd009, 0x00 }, { 0xd00a, 0x68 }, { 0xd00b, 0x00 }, { 0xd00c, 0x15 }, |
| 144 | { 0xd00d, 0x00 }, { 0xd00e, 0x00 }, { 0xd00f, 0x00 }, { 0xd040, 0x9c }, |
| 145 | { 0xd041, 0x21 }, { 0xd042, 0xff }, { 0xd043, 0xf8 }, { 0xd044, 0xd4 }, |
| 146 | { 0xd045, 0x01 }, { 0xd046, 0x48 }, { 0xd047, 0x00 }, { 0xd048, 0xd4 }, |
| 147 | { 0xd049, 0x01 }, { 0xd04a, 0x50 }, { 0xd04b, 0x04 }, { 0xd04c, 0x18 }, |
| 148 | { 0xd04d, 0x60 }, { 0xd04e, 0x00 }, { 0xd04f, 0x01 }, { 0xd050, 0xa8 }, |
| 149 | { 0xd051, 0x63 }, { 0xd052, 0x02 }, { 0xd053, 0xa4 }, { 0xd054, 0x85 }, |
| 150 | { 0xd055, 0x43 }, { 0xd056, 0x00 }, { 0xd057, 0x00 }, { 0xd058, 0x18 }, |
| 151 | { 0xd059, 0x60 }, { 0xd05a, 0x00 }, { 0xd05b, 0x01 }, { 0xd05c, 0xa8 }, |
| 152 | { 0xd05d, 0x63 }, { 0xd05e, 0x03 }, { 0xd05f, 0xf0 }, { 0xd060, 0x98 }, |
| 153 | { 0xd061, 0xa3 }, { 0xd062, 0x00 }, { 0xd063, 0x00 }, { 0xd064, 0x8c }, |
| 154 | { 0xd065, 0x6a }, { 0xd066, 0x00 }, { 0xd067, 0x6e }, { 0xd068, 0xe5 }, |
| 155 | { 0xd069, 0x85 }, { 0xd06a, 0x18 }, { 0xd06b, 0x00 }, { 0xd06c, 0x10 }, |
| 156 | { 0xd06d, 0x00 }, { 0xd06e, 0x00 }, { 0xd06f, 0x10 }, { 0xd070, 0x9c }, |
| 157 | { 0xd071, 0x80 }, { 0xd072, 0x00 }, { 0xd073, 0x03 }, { 0xd074, 0x18 }, |
| 158 | { 0xd075, 0x60 }, { 0xd076, 0x00 }, { 0xd077, 0x01 }, { 0xd078, 0xa8 }, |
| 159 | { 0xd079, 0x63 }, { 0xd07a, 0x07 }, { 0xd07b, 0x80 }, { 0xd07c, 0x07 }, |
| 160 | { 0xd07d, 0xff }, { 0xd07e, 0xf9 }, { 0xd07f, 0x03 }, { 0xd080, 0x8c }, |
| 161 | { 0xd081, 0x63 }, { 0xd082, 0x00 }, { 0xd083, 0x00 }, { 0xd084, 0xa5 }, |
| 162 | { 0xd085, 0x6b }, { 0xd086, 0x00 }, { 0xd087, 0xff }, { 0xd088, 0x18 }, |
| 163 | { 0xd089, 0x80 }, { 0xd08a, 0x00 }, { 0xd08b, 0x01 }, { 0xd08c, 0xa8 }, |
| 164 | { 0xd08d, 0x84 }, { 0xd08e, 0x01 }, { 0xd08f, 0x04 }, { 0xd090, 0xe1 }, |
| 165 | { 0xd091, 0x6b }, { 0xd092, 0x58 }, { 0xd093, 0x00 }, { 0xd094, 0x94 }, |
| 166 | { 0xd095, 0x6a }, { 0xd096, 0x00 }, { 0xd097, 0x70 }, { 0xd098, 0xe1 }, |
| 167 | { 0xd099, 0x6b }, { 0xd09a, 0x20 }, { 0xd09b, 0x00 }, { 0xd09c, 0x95 }, |
| 168 | { 0xd09d, 0x6b }, { 0xd09e, 0x00 }, { 0xd09f, 0x00 }, { 0xd0a0, 0xe4 }, |
| 169 | { 0xd0a1, 0x8b }, { 0xd0a2, 0x18 }, { 0xd0a3, 0x00 }, { 0xd0a4, 0x0c }, |
| 170 | { 0xd0a5, 0x00 }, { 0xd0a6, 0x00 }, { 0xd0a7, 0x23 }, { 0xd0a8, 0x15 }, |
| 171 | { 0xd0a9, 0x00 }, { 0xd0aa, 0x00 }, { 0xd0ab, 0x00 }, { 0xd0ac, 0x18 }, |
| 172 | { 0xd0ad, 0x60 }, { 0xd0ae, 0x80 }, { 0xd0af, 0x06 }, { 0xd0b0, 0xa8 }, |
| 173 | { 0xd0b1, 0x83 }, { 0xd0b2, 0x40 }, { 0xd0b3, 0x08 }, { 0xd0b4, 0xa8 }, |
| 174 | { 0xd0b5, 0xe3 }, { 0xd0b6, 0x38 }, { 0xd0b7, 0x2a }, { 0xd0b8, 0xa8 }, |
| 175 | { 0xd0b9, 0xc3 }, { 0xd0ba, 0x40 }, { 0xd0bb, 0x09 }, { 0xd0bc, 0xa8 }, |
| 176 | { 0xd0bd, 0xa3 }, { 0xd0be, 0x38 }, { 0xd0bf, 0x29 }, { 0xd0c0, 0x8c }, |
| 177 | { 0xd0c1, 0x65 }, { 0xd0c2, 0x00 }, { 0xd0c3, 0x00 }, { 0xd0c4, 0xd8 }, |
| 178 | { 0xd0c5, 0x04 }, { 0xd0c6, 0x18 }, { 0xd0c7, 0x00 }, { 0xd0c8, 0x8c }, |
| 179 | { 0xd0c9, 0x67 }, { 0xd0ca, 0x00 }, { 0xd0cb, 0x00 }, { 0xd0cc, 0xd8 }, |
| 180 | { 0xd0cd, 0x06 }, { 0xd0ce, 0x18 }, { 0xd0cf, 0x00 }, { 0xd0d0, 0x18 }, |
| 181 | { 0xd0d1, 0x60 }, { 0xd0d2, 0x80 }, { 0xd0d3, 0x06 }, { 0xd0d4, 0xa8 }, |
| 182 | { 0xd0d5, 0xe3 }, { 0xd0d6, 0x67 }, { 0xd0d7, 0x02 }, { 0xd0d8, 0xa9 }, |
| 183 | { 0xd0d9, 0x03 }, { 0xd0da, 0x67 }, { 0xd0db, 0x03 }, { 0xd0dc, 0xa8 }, |
| 184 | { 0xd0dd, 0xc3 }, { 0xd0de, 0x3d }, { 0xd0df, 0x05 }, { 0xd0e0, 0x8c }, |
| 185 | { 0xd0e1, 0x66 }, { 0xd0e2, 0x00 }, { 0xd0e3, 0x00 }, { 0xd0e4, 0xb8 }, |
| 186 | { 0xd0e5, 0x63 }, { 0xd0e6, 0x00 }, { 0xd0e7, 0x18 }, { 0xd0e8, 0xb8 }, |
| 187 | { 0xd0e9, 0x63 }, { 0xd0ea, 0x00 }, { 0xd0eb, 0x98 }, { 0xd0ec, 0xbc }, |
| 188 | { 0xd0ed, 0x03 }, { 0xd0ee, 0x00 }, { 0xd0ef, 0x00 }, { 0xd0f0, 0x10 }, |
| 189 | { 0xd0f1, 0x00 }, { 0xd0f2, 0x00 }, { 0xd0f3, 0x16 }, { 0xd0f4, 0xb8 }, |
| 190 | { 0xd0f5, 0x83 }, { 0xd0f6, 0x00 }, { 0xd0f7, 0x19 }, { 0xd0f8, 0x8c }, |
| 191 | { 0xd0f9, 0x67 }, { 0xd0fa, 0x00 }, { 0xd0fb, 0x00 }, { 0xd0fc, 0xb8 }, |
| 192 | { 0xd0fd, 0xa4 }, { 0xd0fe, 0x00 }, { 0xd0ff, 0x98 }, { 0xd100, 0xb8 }, |
| 193 | { 0xd101, 0x83 }, { 0xd102, 0x00 }, { 0xd103, 0x08 }, { 0xd104, 0x8c }, |
| 194 | { 0xd105, 0x68 }, { 0xd106, 0x00 }, { 0xd107, 0x00 }, { 0xd108, 0xe0 }, |
| 195 | { 0xd109, 0x63 }, { 0xd10a, 0x20 }, { 0xd10b, 0x04 }, { 0xd10c, 0xe0 }, |
| 196 | { 0xd10d, 0x65 }, { 0xd10e, 0x18 }, { 0xd10f, 0x00 }, { 0xd110, 0xa4 }, |
| 197 | { 0xd111, 0x83 }, { 0xd112, 0xff }, { 0xd113, 0xff }, { 0xd114, 0xb8 }, |
| 198 | { 0xd115, 0x64 }, { 0xd116, 0x00 }, { 0xd117, 0x48 }, { 0xd118, 0xd8 }, |
| 199 | { 0xd119, 0x07 }, { 0xd11a, 0x18 }, { 0xd11b, 0x00 }, { 0xd11c, 0xd8 }, |
| 200 | { 0xd11d, 0x08 }, { 0xd11e, 0x20 }, { 0xd11f, 0x00 }, { 0xd120, 0x9c }, |
| 201 | { 0xd121, 0x60 }, { 0xd122, 0x00 }, { 0xd123, 0x00 }, { 0xd124, 0xd8 }, |
| 202 | { 0xd125, 0x06 }, { 0xd126, 0x18 }, { 0xd127, 0x00 }, { 0xd128, 0x00 }, |
| 203 | { 0xd129, 0x00 }, { 0xd12a, 0x00 }, { 0xd12b, 0x08 }, { 0xd12c, 0x15 }, |
| 204 | { 0xd12d, 0x00 }, { 0xd12e, 0x00 }, { 0xd12f, 0x00 }, { 0xd130, 0x8c }, |
| 205 | { 0xd131, 0x6a }, { 0xd132, 0x00 }, { 0xd133, 0x76 }, { 0xd134, 0xbc }, |
| 206 | { 0xd135, 0x23 }, { 0xd136, 0x00 }, { 0xd137, 0x00 }, { 0xd138, 0x13 }, |
| 207 | { 0xd139, 0xff }, { 0xd13a, 0xff }, { 0xd13b, 0xe6 }, { 0xd13c, 0x18 }, |
| 208 | { 0xd13d, 0x60 }, { 0xd13e, 0x80 }, { 0xd13f, 0x06 }, { 0xd140, 0x03 }, |
| 209 | { 0xd141, 0xff }, { 0xd142, 0xff }, { 0xd143, 0xdd }, { 0xd144, 0xa8 }, |
| 210 | { 0xd145, 0x83 }, { 0xd146, 0x40 }, { 0xd147, 0x08 }, { 0xd148, 0x85 }, |
| 211 | { 0xd149, 0x21 }, { 0xd14a, 0x00 }, { 0xd14b, 0x00 }, { 0xd14c, 0x85 }, |
| 212 | { 0xd14d, 0x41 }, { 0xd14e, 0x00 }, { 0xd14f, 0x04 }, { 0xd150, 0x44 }, |
| 213 | { 0xd151, 0x00 }, { 0xd152, 0x48 }, { 0xd153, 0x00 }, { 0xd154, 0x9c }, |
| 214 | { 0xd155, 0x21 }, { 0xd156, 0x00 }, { 0xd157, 0x08 }, { 0x6f0e, 0x03 }, |
| 215 | { 0x6f0f, 0x00 }, { 0x460e, 0x08 }, { 0x460f, 0x01 }, { 0x4610, 0x00 }, |
| 216 | { 0x4611, 0x01 }, { 0x4612, 0x00 }, { 0x4613, 0x01 }, |
| 217 | /* 8 bits */ |
| 218 | { 0x4605, 0x08 }, |
| 219 | /* Swap data bits order [9:0] -> [0:9] */ |
| 220 | { 0x4709, 0x10 }, { 0x4608, 0x00 }, { 0x4609, 0x08 }, { 0x6804, 0x00 }, |
| 221 | { 0x6805, 0x06 }, { 0x6806, 0x00 }, { 0x5120, 0x00 }, { 0x3510, 0x00 }, |
| 222 | { 0x3504, 0x00 }, { 0x6800, 0x00 }, { 0x6f0d, 0x01 }, |
| 223 | /* PCLK falling edge */ |
| 224 | { 0x4708, 0x01 }, { 0x5000, 0xff }, { 0x5001, 0xbf }, { 0x5002, 0x7e }, |
| 225 | { 0x503d, 0x00 }, { 0xc450, 0x01 }, { 0xc452, 0x04 }, { 0xc453, 0x00 }, |
| 226 | { 0xc454, 0x00 }, { 0xc455, 0x01 }, { 0xc456, 0x01 }, { 0xc457, 0x00 }, |
| 227 | { 0xc458, 0x00 }, { 0xc459, 0x00 }, { 0xc45b, 0x00 }, { 0xc45c, 0x01 }, |
| 228 | { 0xc45d, 0x00 }, { 0xc45e, 0x00 }, { 0xc45f, 0x00 }, { 0xc460, 0x00 }, |
| 229 | { 0xc461, 0x01 }, { 0xc462, 0x01 }, { 0xc464, 0x03 }, { 0xc465, 0x00 }, |
| 230 | { 0xc466, 0x8a }, { 0xc467, 0x00 }, { 0xc468, 0x86 }, { 0xc469, 0x00 }, |
| 231 | { 0xc46a, 0x40 }, { 0xc46b, 0x50 }, { 0xc46c, 0x30 }, { 0xc46d, 0x28 }, |
| 232 | { 0xc46e, 0x60 }, { 0xc46f, 0x40 }, { 0xc47c, 0x01 }, { 0xc47d, 0x38 }, |
| 233 | { 0xc47e, 0x00 }, { 0xc47f, 0x00 }, { 0xc480, 0x00 }, { 0xc481, 0xff }, |
| 234 | { 0xc482, 0x00 }, { 0xc483, 0x40 }, { 0xc484, 0x00 }, { 0xc485, 0x18 }, |
| 235 | { 0xc486, 0x00 }, { 0xc487, 0x18 }, |
| 236 | { 0xc488, (OV10635_VTS - 8) * 16 >> 8}, |
| 237 | { 0xc489, (OV10635_VTS - 8) * 16 & 0xff}, |
| 238 | { 0xc48a, (OV10635_VTS - 8) * 16 >> 8}, |
| 239 | { 0xc48b, (OV10635_VTS - 8) * 16 & 0xff}, { 0xc48c, 0x00 }, |
| 240 | { 0xc48d, 0x04 }, { 0xc48e, 0x00 }, { 0xc48f, 0x04 }, { 0xc490, 0x03 }, |
| 241 | { 0xc492, 0x20 }, { 0xc493, 0x08 }, { 0xc498, 0x02 }, { 0xc499, 0x00 }, |
| 242 | { 0xc49a, 0x02 }, { 0xc49b, 0x00 }, { 0xc49c, 0x02 }, { 0xc49d, 0x00 }, |
| 243 | { 0xc49e, 0x02 }, { 0xc49f, 0x60 }, { 0xc4a0, 0x03 }, { 0xc4a1, 0x00 }, |
| 244 | { 0xc4a2, 0x04 }, { 0xc4a3, 0x00 }, { 0xc4a4, 0x00 }, { 0xc4a5, 0x10 }, |
| 245 | { 0xc4a6, 0x00 }, { 0xc4a7, 0x40 }, { 0xc4a8, 0x00 }, { 0xc4a9, 0x80 }, |
| 246 | { 0xc4aa, 0x0d }, { 0xc4ab, 0x00 }, { 0xc4ac, 0x0f }, { 0xc4ad, 0xc0 }, |
| 247 | { 0xc4b4, 0x01 }, { 0xc4b5, 0x01 }, { 0xc4b6, 0x00 }, { 0xc4b7, 0x01 }, |
| 248 | { 0xc4b8, 0x00 }, { 0xc4b9, 0x01 }, { 0xc4ba, 0x01 }, { 0xc4bb, 0x00 }, |
| 249 | { 0xc4bc, 0x01 }, { 0xc4bd, 0x60 }, { 0xc4be, 0x02 }, { 0xc4bf, 0x33 }, |
| 250 | { 0xc4c8, 0x03 }, { 0xc4c9, 0xd0 }, { 0xc4ca, 0x0e }, { 0xc4cb, 0x00 }, |
| 251 | { 0xc4cc, 0x0e }, { 0xc4cd, 0x51 }, { 0xc4ce, 0x0e }, { 0xc4cf, 0x51 }, |
| 252 | { 0xc4d0, 0x04 }, { 0xc4d1, 0x80 }, { 0xc4e0, 0x04 }, { 0xc4e1, 0x02 }, |
| 253 | { 0xc4e2, 0x01 }, { 0xc4e4, 0x10 }, { 0xc4e5, 0x20 }, { 0xc4e6, 0x30 }, |
| 254 | { 0xc4e7, 0x40 }, { 0xc4e8, 0x50 }, { 0xc4e9, 0x60 }, { 0xc4ea, 0x70 }, |
| 255 | { 0xc4eb, 0x80 }, { 0xc4ec, 0x90 }, { 0xc4ed, 0xa0 }, { 0xc4ee, 0xb0 }, |
| 256 | { 0xc4ef, 0xc0 }, { 0xc4f0, 0xd0 }, { 0xc4f1, 0xe0 }, { 0xc4f2, 0xf0 }, |
| 257 | { 0xc4f3, 0x80 }, { 0xc4f4, 0x00 }, { 0xc4f5, 0x20 }, { 0xc4f6, 0x02 }, |
| 258 | { 0xc4f7, 0x00 }, { 0xc4f8, 0x00 }, { 0xc4f9, 0x00 }, { 0xc4fa, 0x00 }, |
| 259 | { 0xc4fb, 0x01 }, { 0xc4fc, 0x01 }, { 0xc4fd, 0x00 }, { 0xc4fe, 0x04 }, |
| 260 | { 0xc4ff, 0x02 }, { 0xc500, 0x48 }, { 0xc501, 0x74 }, { 0xc502, 0x58 }, |
| 261 | { 0xc503, 0x80 }, { 0xc504, 0x05 }, { 0xc505, 0x80 }, { 0xc506, 0x03 }, |
| 262 | { 0xc507, 0x80 }, { 0xc508, 0x01 }, { 0xc509, 0xc0 }, { 0xc50a, 0x01 }, |
| 263 | { 0xc50b, 0xa0 }, { 0xc50c, 0x01 }, { 0xc50d, 0x2c }, { 0xc50e, 0x01 }, |
| 264 | { 0xc50f, 0x0a }, { 0xc510, 0x00 }, { 0xc511, 0x00 }, { 0xc512, 0xe5 }, |
| 265 | { 0xc513, 0x14 }, { 0xc514, 0x04 }, { 0xc515, 0x00 }, { 0xc518, OV10635_VTS >> 8}, |
| 266 | { 0xc519, OV10635_VTS & 0xff}, { 0xc51a, OV10635_HTS >> 8}, |
| 267 | { 0xc51b, OV10635_HTS & 0xff}, { 0xc2e0, 0x00 }, { 0xc2e1, 0x51 }, |
| 268 | { 0xc2e2, 0x00 }, { 0xc2e3, 0xd6 }, { 0xc2e4, 0x01 }, { 0xc2e5, 0x5e }, |
| 269 | { 0xc2e9, 0x01 }, { 0xc2ea, 0x7a }, { 0xc2eb, 0x90 }, { 0xc2ed, 0x00 }, |
| 270 | { 0xc2ee, 0x7a }, { 0xc2ef, 0x64 }, { 0xc308, 0x00 }, { 0xc309, 0x00 }, |
| 271 | { 0xc30a, 0x00 }, { 0xc30c, 0x00 }, { 0xc30d, 0x01 }, { 0xc30e, 0x00 }, |
| 272 | { 0xc30f, 0x00 }, { 0xc310, 0x01 }, { 0xc311, 0x60 }, { 0xc312, 0xff }, |
| 273 | { 0xc313, 0x08 }, { 0xc314, 0x01 }, { 0xc315, 0x00 }, { 0xc316, 0xff }, |
| 274 | { 0xc317, 0x0b }, { 0xc318, 0x00 }, { 0xc319, 0x0c }, { 0xc31a, 0x00 }, |
| 275 | { 0xc31b, 0xe0 }, { 0xc31c, 0x00 }, { 0xc31d, 0x14 }, { 0xc31e, 0x00 }, |
| 276 | { 0xc31f, 0xc5 }, { 0xc320, 0xff }, { 0xc321, 0x4b }, { 0xc322, 0xff }, |
| 277 | { 0xc323, 0xf0 }, { 0xc324, 0xff }, { 0xc325, 0xe8 }, { 0xc326, 0x00 }, |
| 278 | { 0xc327, 0x46 }, { 0xc328, 0xff }, { 0xc329, 0xd2 }, { 0xc32a, 0xff }, |
| 279 | { 0xc32b, 0xe4 }, { 0xc32c, 0xff }, { 0xc32d, 0xbb }, { 0xc32e, 0x00 }, |
| 280 | { 0xc32f, 0x61 }, { 0xc330, 0xff }, { 0xc331, 0xf9 }, { 0xc332, 0x00 }, |
| 281 | { 0xc333, 0xd9 }, { 0xc334, 0x00 }, { 0xc335, 0x2e }, { 0xc336, 0x00 }, |
| 282 | { 0xc337, 0xb1 }, { 0xc338, 0xff }, { 0xc339, 0x64 }, { 0xc33a, 0xff }, |
| 283 | { 0xc33b, 0xeb }, { 0xc33c, 0xff }, { 0xc33d, 0xe8 }, { 0xc33e, 0x00 }, |
| 284 | { 0xc33f, 0x48 }, { 0xc340, 0xff }, { 0xc341, 0xd0 }, { 0xc342, 0xff }, |
| 285 | { 0xc343, 0xed }, { 0xc344, 0xff }, { 0xc345, 0xad }, { 0xc346, 0x00 }, |
| 286 | { 0xc347, 0x66 }, { 0xc348, 0x01 }, { 0xc349, 0x00 }, { 0x6700, 0x04 }, |
| 287 | { 0x6701, 0x7b }, { 0x6702, 0xfd }, { 0x6703, 0xf9 }, { 0x6704, 0x3d }, |
| 288 | { 0x6705, 0x71 }, { 0x6706, 0x78 }, { 0x6708, 0x05 }, { 0x6f06, 0x6f }, |
| 289 | { 0x6f07, 0x00 }, { 0x6f0a, 0x6f }, { 0x6f0b, 0x00 }, { 0x6f00, 0x03 }, |
| 290 | { 0xc34c, 0x01 }, { 0xc34d, 0x00 }, { 0xc34e, 0x46 }, { 0xc34f, 0x55 }, |
| 291 | { 0xc350, 0x00 }, { 0xc351, 0x40 }, { 0xc352, 0x00 }, { 0xc353, 0xff }, |
| 292 | { 0xc354, 0x04 }, { 0xc355, 0x08 }, { 0xc356, 0x01 }, { 0xc357, 0xef }, |
| 293 | { 0xc358, 0x30 }, { 0xc359, 0x01 }, { 0xc35a, 0x64 }, { 0xc35b, 0x46 }, |
| 294 | { 0xc35c, 0x00 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, |
| 295 | { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, |
| 296 | { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, |
| 297 | { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, |
| 298 | { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, |
| 299 | { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, |
| 300 | { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0xc261, 0x01 }, |
| 301 | { 0x301b, 0xf0 }, { 0x301c, 0xf0 }, { 0x301a, 0xf0 }, { 0x6f00, 0xc3 }, |
| 302 | { 0xc46a, 0x30 }, { 0xc46d, 0x20 }, { 0xc464, 0x84 }, { 0xc465, 0x00 }, |
| 303 | { 0x6f00, 0x03 }, { 0x6f00, 0x43 }, { 0x381c, 0x00 }, { 0x381d, 0x40 }, |
| 304 | { 0xc454, 0x01 }, { 0x6f00, 0xc3 }, { 0xc454, 0x00 }, { 0xc4b1, 0x02 }, |
| 305 | { 0xc4b2, 0x01 }, { 0xc4b3, 0x03 }, { 0x6f00, 0x03 }, { 0x6f00, 0x43 }, |
| 306 | /* enable FSIN (FRAMESYNC input) functionality */ |
| 307 | { 0x3832, (0x0d + 2 * 0x20 + 0x15 + 38) >> 8 }, |
| 308 | { 0x3833, (0x0d + 2 * 0x20 + 0x15 + 38) & 0xff }, |
| 309 | { 0x3834, OV10635_VTS >> 8 }, { 0x3835, OV10635_VTS & 0xff }, |
| 310 | { 0x302e, 0x01 }, |
| 311 | }; |
| 312 | |
| 313 | struct rdacm20_device { |
| 314 | struct device *dev; |
| 315 | struct max9271_device *serializer; |
| 316 | struct i2c_client *sensor; |
| 317 | struct v4l2_subdev sd; |
| 318 | struct media_pad pad; |
| 319 | struct v4l2_ctrl_handler ctrls; |
| 320 | u32 addrs[2]; |
| 321 | }; |
| 322 | |
| 323 | static inline struct rdacm20_device *sd_to_rdacm20(struct v4l2_subdev *sd) |
| 324 | { |
| 325 | return container_of(sd, struct rdacm20_device, sd); |
| 326 | } |
| 327 | |
| 328 | static inline struct rdacm20_device *i2c_to_rdacm20(struct i2c_client *client) |
| 329 | { |
| 330 | return sd_to_rdacm20(i2c_get_clientdata(client)); |
| 331 | } |
| 332 | |
| 333 | static int ov10635_read16(struct rdacm20_device *dev, u16 reg) |
| 334 | { |
| 335 | u8 buf[2] = { reg >> 8, reg & 0xff }; |
| 336 | int ret; |
| 337 | |
| 338 | ret = i2c_master_send(dev->sensor, buf, 2); |
| 339 | if (ret != 2) { |
| 340 | dev_dbg(dev->dev, "%s: register 0x%04x write failed (%d)\n", |
| 341 | __func__, reg, ret); |
| 342 | return ret; |
| 343 | } |
| 344 | |
| 345 | ret = i2c_master_recv(dev->sensor, buf, 2); |
| 346 | if (ret < 0) { |
| 347 | dev_dbg(dev->dev, "%s: register 0x%04x read failed (%d)\n", |
| 348 | __func__, reg, ret); |
| 349 | return ret; |
| 350 | } |
| 351 | |
| 352 | return (buf[0] << 8) | buf[1]; |
| 353 | } |
| 354 | |
| 355 | static int __ov10635_write(struct rdacm20_device *dev, u16 reg, u8 val) |
| 356 | { |
| 357 | u8 buf[3] = { reg >> 8, reg & 0xff, val }; |
| 358 | int ret; |
| 359 | |
| 360 | dev_dbg(dev->dev, "%s(0x%04x, 0x%02x)\n", __func__, reg, val); |
| 361 | |
| 362 | ret = i2c_master_send(dev->sensor, buf, 3); |
| 363 | return ret < 0 ? ret : 0; |
| 364 | } |
| 365 | |
| 366 | static int ov10635_write(struct rdacm20_device *dev, u16 reg, u8 val) |
| 367 | { |
| 368 | int ret; |
| 369 | |
| 370 | ret = __ov10635_write(dev, reg, val); |
| 371 | if (ret < 0) |
| 372 | dev_err(dev->dev, "%s: register 0x%04x write failed (%d)\n", |
| 373 | __func__, reg, ret); |
| 374 | |
| 375 | return ret; |
| 376 | } |
| 377 | |
| 378 | static int ov10635_set_regs(struct rdacm20_device *dev, |
| 379 | const struct ov10635_reg *regs, |
| 380 | unsigned int nr_regs) |
| 381 | { |
| 382 | unsigned int i; |
| 383 | int ret; |
| 384 | |
| 385 | for (i = 0; i < nr_regs; i++) { |
| 386 | ret = __ov10635_write(dev, regs[i].reg, regs[i].val); |
| 387 | if (ret) { |
| 388 | dev_err(dev->dev, |
| 389 | "%s: register %u (0x%04x) write failed (%d)\n", |
| 390 | __func__, i, regs[i].reg, ret); |
| 391 | return ret; |
| 392 | } |
| 393 | } |
| 394 | |
| 395 | return 0; |
| 396 | } |
| 397 | |
| 398 | static int rdacm20_s_stream(struct v4l2_subdev *sd, int enable) |
| 399 | { |
| 400 | struct rdacm20_device *dev = sd_to_rdacm20(sd); |
| 401 | |
| 402 | return max9271_set_serial_link(dev->serializer, enable); |
| 403 | } |
| 404 | |
| 405 | static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd, |
| 406 | struct v4l2_subdev_pad_config *cfg, |
| 407 | struct v4l2_subdev_mbus_code_enum *code) |
| 408 | { |
| 409 | if (code->pad || code->index > 0) |
| 410 | return -EINVAL; |
| 411 | |
| 412 | code->code = MEDIA_BUS_FMT_UYVY8_2X8; |
| 413 | |
| 414 | return 0; |
| 415 | } |
| 416 | |
| 417 | static int rdacm20_get_fmt(struct v4l2_subdev *sd, |
| 418 | struct v4l2_subdev_pad_config *cfg, |
| 419 | struct v4l2_subdev_format *format) |
| 420 | { |
| 421 | struct v4l2_mbus_framefmt *mf = &format->format; |
| 422 | |
| 423 | if (format->pad) |
| 424 | return -EINVAL; |
| 425 | |
| 426 | mf->width = OV10635_WIDTH; |
| 427 | mf->height = OV10635_HEIGHT; |
| 428 | mf->code = MEDIA_BUS_FMT_UYVY8_2X8; |
| 429 | mf->colorspace = V4L2_COLORSPACE_RAW; |
| 430 | mf->field = V4L2_FIELD_NONE; |
| 431 | mf->ycbcr_enc = V4L2_YCBCR_ENC_601; |
| 432 | mf->quantization = V4L2_QUANTIZATION_FULL_RANGE; |
| 433 | mf->xfer_func = V4L2_XFER_FUNC_NONE; |
| 434 | |
| 435 | return 0; |
| 436 | } |
| 437 | |
| 438 | static struct v4l2_subdev_video_ops rdacm20_video_ops = { |
| 439 | .s_stream = rdacm20_s_stream, |
| 440 | }; |
| 441 | |
| 442 | static const struct v4l2_subdev_pad_ops rdacm20_subdev_pad_ops = { |
| 443 | .enum_mbus_code = rdacm20_enum_mbus_code, |
| 444 | .get_fmt = rdacm20_get_fmt, |
| 445 | .set_fmt = rdacm20_get_fmt, |
| 446 | }; |
| 447 | |
| 448 | static struct v4l2_subdev_ops rdacm20_subdev_ops = { |
| 449 | .video = &rdacm20_video_ops, |
| 450 | .pad = &rdacm20_subdev_pad_ops, |
| 451 | }; |
| 452 | |
| 453 | static int rdacm20_initialize(struct rdacm20_device *dev) |
| 454 | { |
| 455 | unsigned int retry = 3; |
| 456 | int ret; |
| 457 | |
| 458 | /* Verify communication with the MAX9271: ping to wakeup. */ |
| 459 | dev->serializer->client->addr = MAX9271_DEFAULT_ADDR; |
| 460 | i2c_smbus_read_byte(dev->serializer->client); |
| 461 | |
| 462 | /* Serial link disabled during config as it needs a valid pixel clock. */ |
| 463 | ret = max9271_set_serial_link(dev->serializer, false); |
| 464 | if (ret) |
| 465 | return ret; |
| 466 | |
| 467 | /* |
| 468 | * Ensure that we have a good link configuration before attempting to |
| 469 | * identify the device. |
| 470 | */ |
| 471 | max9271_configure_i2c(dev->serializer, MAX9271_I2CSLVSH_469NS_234NS | |
| 472 | MAX9271_I2CSLVTO_1024US | |
| 473 | MAX9271_I2CMSTBT_105KBPS); |
| 474 | |
| 475 | max9271_configure_gmsl_link(dev->serializer); |
| 476 | |
| 477 | ret = max9271_verify_id(dev->serializer); |
| 478 | if (ret < 0) |
| 479 | return ret; |
| 480 | |
| 481 | ret = max9271_set_address(dev->serializer, dev->addrs[0]); |
| 482 | if (ret < 0) |
| 483 | return ret; |
| 484 | dev->serializer->client->addr = dev->addrs[0]; |
| 485 | |
| 486 | /* |
| 487 | * Reset the sensor by cycling the OV10635 reset signal connected to the |
| 488 | * MAX9271 GPIO1 and verify communication with the OV10635. |
| 489 | */ |
Jacopo Mondi | 4440b48 | 2020-11-20 17:15:29 +0100 | [diff] [blame] | 490 | ret = max9271_enable_gpios(dev->serializer, MAX9271_GPIO1OUT); |
| 491 | if (ret) |
| 492 | return ret; |
| 493 | |
| 494 | ret = max9271_clear_gpios(dev->serializer, MAX9271_GPIO1OUT); |
| 495 | if (ret) |
| 496 | return ret; |
Jacopo Mondi | 34009bf | 2020-06-12 16:47:13 +0200 | [diff] [blame] | 497 | usleep_range(10000, 15000); |
Jacopo Mondi | 4440b48 | 2020-11-20 17:15:29 +0100 | [diff] [blame] | 498 | |
| 499 | ret = max9271_set_gpios(dev->serializer, MAX9271_GPIO1OUT); |
| 500 | if (ret) |
| 501 | return ret; |
Jacopo Mondi | 34009bf | 2020-06-12 16:47:13 +0200 | [diff] [blame] | 502 | usleep_range(10000, 15000); |
| 503 | |
| 504 | again: |
| 505 | ret = ov10635_read16(dev, OV10635_PID); |
| 506 | if (ret < 0) { |
| 507 | if (retry--) |
| 508 | goto again; |
| 509 | |
| 510 | dev_err(dev->dev, "OV10635 ID read failed (%d)\n", |
| 511 | ret); |
| 512 | return -ENXIO; |
| 513 | } |
| 514 | |
| 515 | if (ret != OV10635_VERSION) { |
| 516 | if (retry--) |
| 517 | goto again; |
| 518 | |
| 519 | dev_err(dev->dev, "OV10635 ID mismatch (0x%04x)\n", |
| 520 | ret); |
| 521 | return -ENXIO; |
| 522 | } |
| 523 | |
| 524 | /* Change the sensor I2C address. */ |
| 525 | ret = ov10635_write(dev, OV10635_SC_CMMN_SCCB_ID, |
| 526 | (dev->addrs[1] << 1) | |
| 527 | OV10635_SC_CMMN_SCCB_ID_SELECT); |
| 528 | if (ret < 0) { |
| 529 | dev_err(dev->dev, |
| 530 | "OV10635 I2C address change failed (%d)\n", ret); |
| 531 | return ret; |
| 532 | } |
| 533 | dev->sensor->addr = dev->addrs[1]; |
| 534 | usleep_range(3500, 5000); |
| 535 | |
| 536 | /* Program the 0V10635 initial configuration. */ |
| 537 | ret = ov10635_set_regs(dev, ov10635_regs_wizard, |
| 538 | ARRAY_SIZE(ov10635_regs_wizard)); |
| 539 | if (ret) |
| 540 | return ret; |
| 541 | |
| 542 | dev_info(dev->dev, "Identified MAX9271 + OV10635 device\n"); |
| 543 | |
| 544 | return 0; |
| 545 | } |
| 546 | |
| 547 | static int rdacm20_probe(struct i2c_client *client) |
| 548 | { |
| 549 | struct rdacm20_device *dev; |
| 550 | struct fwnode_handle *ep; |
| 551 | int ret; |
| 552 | |
| 553 | dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); |
| 554 | if (!dev) |
| 555 | return -ENOMEM; |
| 556 | dev->dev = &client->dev; |
| 557 | |
| 558 | dev->serializer = devm_kzalloc(&client->dev, sizeof(*dev->serializer), |
| 559 | GFP_KERNEL); |
| 560 | if (!dev->serializer) |
| 561 | return -ENOMEM; |
| 562 | |
| 563 | dev->serializer->client = client; |
| 564 | |
| 565 | ret = of_property_read_u32_array(client->dev.of_node, "reg", |
| 566 | dev->addrs, 2); |
| 567 | if (ret < 0) { |
| 568 | dev_err(dev->dev, "Invalid DT reg property: %d\n", ret); |
| 569 | return -EINVAL; |
| 570 | } |
| 571 | |
| 572 | /* Create the dummy I2C client for the sensor. */ |
| 573 | dev->sensor = i2c_new_dummy_device(client->adapter, |
| 574 | OV10635_I2C_ADDRESS); |
| 575 | if (IS_ERR(dev->sensor)) { |
| 576 | ret = PTR_ERR(dev->sensor); |
| 577 | goto error; |
| 578 | } |
| 579 | |
| 580 | /* Initialize the hardware. */ |
| 581 | ret = rdacm20_initialize(dev); |
| 582 | if (ret < 0) |
| 583 | goto error; |
| 584 | |
| 585 | /* Initialize and register the subdevice. */ |
| 586 | v4l2_i2c_subdev_init(&dev->sd, client, &rdacm20_subdev_ops); |
| 587 | dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
| 588 | |
| 589 | v4l2_ctrl_handler_init(&dev->ctrls, 1); |
| 590 | v4l2_ctrl_new_std(&dev->ctrls, NULL, V4L2_CID_PIXEL_RATE, |
| 591 | OV10635_PIXEL_RATE, OV10635_PIXEL_RATE, 1, |
| 592 | OV10635_PIXEL_RATE); |
| 593 | dev->sd.ctrl_handler = &dev->ctrls; |
| 594 | |
| 595 | ret = dev->ctrls.error; |
| 596 | if (ret) |
| 597 | goto error_free_ctrls; |
| 598 | |
| 599 | dev->pad.flags = MEDIA_PAD_FL_SOURCE; |
| 600 | dev->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; |
| 601 | ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); |
| 602 | if (ret < 0) |
| 603 | goto error_free_ctrls; |
| 604 | |
| 605 | ep = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); |
| 606 | if (!ep) { |
| 607 | dev_err(&client->dev, |
| 608 | "Unable to get endpoint in node %pOF\n", |
| 609 | client->dev.of_node); |
| 610 | ret = -ENOENT; |
| 611 | goto error_free_ctrls; |
| 612 | } |
| 613 | dev->sd.fwnode = ep; |
| 614 | |
| 615 | ret = v4l2_async_register_subdev(&dev->sd); |
| 616 | if (ret) |
| 617 | goto error_put_node; |
| 618 | |
| 619 | return 0; |
| 620 | |
| 621 | error_put_node: |
| 622 | fwnode_handle_put(ep); |
| 623 | error_free_ctrls: |
| 624 | v4l2_ctrl_handler_free(&dev->ctrls); |
| 625 | error: |
| 626 | media_entity_cleanup(&dev->sd.entity); |
| 627 | if (dev->sensor) |
| 628 | i2c_unregister_device(dev->sensor); |
| 629 | |
| 630 | dev_err(&client->dev, "probe failed\n"); |
| 631 | |
| 632 | return ret; |
| 633 | } |
| 634 | |
| 635 | static int rdacm20_remove(struct i2c_client *client) |
| 636 | { |
| 637 | struct rdacm20_device *dev = i2c_to_rdacm20(client); |
| 638 | |
| 639 | fwnode_handle_put(dev->sd.fwnode); |
| 640 | v4l2_async_unregister_subdev(&dev->sd); |
| 641 | v4l2_ctrl_handler_free(&dev->ctrls); |
| 642 | media_entity_cleanup(&dev->sd.entity); |
| 643 | i2c_unregister_device(dev->sensor); |
| 644 | |
| 645 | return 0; |
| 646 | } |
| 647 | |
| 648 | static void rdacm20_shutdown(struct i2c_client *client) |
| 649 | { |
| 650 | struct rdacm20_device *dev = i2c_to_rdacm20(client); |
| 651 | |
| 652 | /* make sure stream off during shutdown (reset/reboot) */ |
| 653 | rdacm20_s_stream(&dev->sd, 0); |
| 654 | } |
| 655 | |
| 656 | static const struct of_device_id rdacm20_of_ids[] = { |
| 657 | { .compatible = "imi,rdacm20", }, |
| 658 | { } |
| 659 | }; |
| 660 | MODULE_DEVICE_TABLE(of, rdacm20_of_ids); |
| 661 | |
| 662 | static struct i2c_driver rdacm20_i2c_driver = { |
| 663 | .driver = { |
| 664 | .name = "rdacm20", |
| 665 | .of_match_table = rdacm20_of_ids, |
| 666 | }, |
| 667 | .probe_new = rdacm20_probe, |
| 668 | .remove = rdacm20_remove, |
| 669 | .shutdown = rdacm20_shutdown, |
| 670 | }; |
| 671 | |
| 672 | module_i2c_driver(rdacm20_i2c_driver); |
| 673 | |
| 674 | MODULE_DESCRIPTION("GMSL Camera driver for RDACM20"); |
| 675 | MODULE_AUTHOR("Vladimir Barinov"); |
| 676 | MODULE_LICENSE("GPL"); |