1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "imx227.h"
6 #include "imx227-seq.h"
7 #include <ddk/binding.h>
8 #include <ddk/debug.h>
9 #include <ddk/metadata.h>
10 #include <ddk/metadata/camera.h>
11 #include <ddk/protocol/i2c-lib.h>
12 #include <fbl/alloc_checker.h>
13 #include <fbl/auto_call.h>
14 #include <fbl/auto_lock.h>
15 #include <fbl/unique_ptr.h>
16 #include <hw/reg.h>
17 #include <stdint.h>
18 #include <threads.h>
19 #include <zircon/device/camera.h>
20 #include <zircon/types.h>
21 
22 namespace camera {
23 
24 namespace {
25 
26 constexpr uint16_t kSensorId = 0x0227;
27 constexpr uint32_t kAGainPrecision = 12;
28 constexpr uint32_t kDGainPrecision = 8;
29 constexpr int32_t kLog2GainShift = 18;
30 constexpr int32_t kSensorExpNumber = 1;
31 constexpr uint32_t kMasterClock = 288000000;
32 
33 } // namespace
34 
InitPdev(zx_device_t * parent)35 zx_status_t Imx227Device::InitPdev(zx_device_t* parent) {
36     if (!pdev_.is_valid()) {
37         zxlogf(ERROR, "%s: ZX_PROTOCOL_PDEV not available\n", __FUNCTION__);
38         return ZX_ERR_NO_RESOURCES;
39     }
40 
41     for (uint32_t i = 0; i < countof(gpios_); i++) {
42         std::optional<ddk::GpioProtocolClient> gpio;
43         gpio = pdev_.GetGpio(i);
44         if (!gpio) {
45             return ZX_ERR_NO_RESOURCES;
46         }
47         gpios_[i] = *gpio;
48         // Set the GPIO to output and set initial value to 0.
49         gpios_[i].ConfigOut(0);
50     }
51 
52     // I2c for communicating with the sensor.
53     if (i2c_.is_valid()) {
54         return ZX_ERR_NO_RESOURCES;
55     }
56 
57     // Clk for gating clocks for sensor.
58     if (clk_.is_valid()) {
59         return ZX_ERR_NO_RESOURCES;
60     }
61 
62     // Mipi for init and de-init.
63     if (!mipi_.is_valid()) {
64         return ZX_ERR_NO_RESOURCES;
65     }
66 
67     return ZX_OK;
68 }
69 
ReadReg(uint16_t addr)70 uint8_t Imx227Device::ReadReg(uint16_t addr) {
71     // Convert the address to Big Endian format.
72     // The camera sensor expects in this format.
73     uint16_t buf = htobe16(addr);
74     uint8_t val = 0;
75     zx_status_t status = i2c_.WriteReadSync(reinterpret_cast<uint8_t*>(&buf), sizeof(buf),
76                                             &val, sizeof(val));
77     if (status != ZX_OK) {
78         zxlogf(ERROR, "Imx227Device: could not read reg addr: 0x%08x  status: %d\n", addr, status);
79         return -1;
80     }
81     return val;
82 }
83 
WriteReg(uint16_t addr,uint8_t val)84 void Imx227Device::WriteReg(uint16_t addr, uint8_t val) {
85     // Convert the address to Big Endian format.
86     // The camera sensor expects in this format.
87     // First two bytes are the address, third one is the value to be written.
88     uint8_t buf[3];
89     buf[1] = static_cast<uint8_t>(addr & 0xFF);
90     buf[0] = static_cast<uint8_t>((addr >> 8) & 0xFF);
91     buf[2] = val;
92 
93     zx_status_t status = i2c_.WriteSync(buf, 3);
94     if (status != ZX_OK) {
95         zxlogf(ERROR, "Imx227Device: could not write reg addr/val: 0x%08x/0x%08x status: %d\n",
96                addr, val, status);
97     }
98 }
99 
ValidateSensorID()100 bool Imx227Device::ValidateSensorID() {
101     uint16_t sensor_id = static_cast<uint16_t>((ReadReg(0x0016) << 8) | ReadReg(0x0017));
102     if (sensor_id != kSensorId) {
103         zxlogf(ERROR, "Imx227Device: Invalid sensor ID\n");
104         return false;
105     }
106     return true;
107 }
108 
InitSensor(uint8_t idx)109 zx_status_t Imx227Device::InitSensor(uint8_t idx) {
110     if (idx >= countof(kSEQUENCE_TABLE)) {
111         return ZX_ERR_INVALID_ARGS;
112     }
113 
114     const init_seq_fmt_t* sequence = kSEQUENCE_TABLE[idx];
115     bool init_command = true;
116 
117     while (init_command) {
118         uint16_t address = sequence->address;
119         uint8_t value = sequence->value;
120 
121         switch (address) {
122         case 0x0000: {
123             if (sequence->value == 0 && sequence->len == 0) {
124                 init_command = false;
125             } else {
126                 WriteReg(address, value);
127             }
128             break;
129         }
130         default:
131             WriteReg(address, value);
132             break;
133         }
134         sequence++;
135     }
136     return ZX_OK;
137 }
138 
Init()139 zx_status_t Imx227Device::Init() {
140 
141     // Power up sequence. Reference: Page 51- IMX227-0AQH5-C datasheet.
142     gpios_[VANA_ENABLE].ConfigOut(1);
143     zx_nanosleep(zx_deadline_after(ZX_MSEC(50)));
144 
145     gpios_[VDIG_ENABLE].ConfigOut(1);
146     zx_nanosleep(zx_deadline_after(ZX_MSEC(50)));
147 
148     // Enable 24M clock for sensor.
149     clk_.Enable(0);
150     zx_nanosleep(zx_deadline_after(ZX_MSEC(10)));
151 
152     gpios_[CAM_SENSOR_RST].ConfigOut(0);
153     zx_nanosleep(zx_deadline_after(ZX_MSEC(50)));
154 
155     // Get Sensor ID to validate initialization sequence.
156     if (!ValidateSensorID()) {
157         return ZX_ERR_INTERNAL;
158     }
159 
160     // Initialize Sensor Context.
161     ctx_.seq_width = 1;
162     ctx_.streaming_flag = 0;
163     ctx_.again_old = 0;
164     ctx_.change_flag = 0;
165     ctx_.again_limit = 8 << kAGainPrecision;
166     ctx_.dgain_limit = 15 << kDGainPrecision;
167 
168     // Initialize Sensor Parameters.
169     ctx_.param.again_accuracy = 1 << kLog2GainShift;
170     ctx_.param.sensor_exp_number = kSensorExpNumber;
171     ctx_.param.again_log2_max = 3 << kLog2GainShift;
172     ctx_.param.dgain_log2_max = 3 << kLog2GainShift;
173     ctx_.param.integration_time_apply_delay = 2;
174     ctx_.param.isp_exposure_channel_delay = 0;
175 
176     return ZX_OK;
177 }
178 
DeInit()179 void Imx227Device::DeInit() {
180     mipi_.DeInit();
181 }
182 
GetInfo(fuchsia_hardware_camera_SensorInfo * out_info)183 zx_status_t Imx227Device::GetInfo(fuchsia_hardware_camera_SensorInfo* out_info) {
184     return ZX_ERR_NOT_SUPPORTED;
185 }
186 
SetMode(uint8_t mode)187 zx_status_t Imx227Device::SetMode(uint8_t mode) {
188     // Get Sensor ID to see if sensor is initialized.
189     if (!ValidateSensorID()) {
190         return ZX_ERR_INTERNAL;
191     }
192 
193     if (mode >= countof(supported_modes)) {
194         return ZX_ERR_INVALID_ARGS;
195     }
196 
197     switch (supported_modes[mode].wdr_mode) {
198     case kWDR_MODE_LINEAR: {
199 
200         InitSensor(supported_modes[mode].idx);
201 
202         ctx_.again_delay = 0;
203         ctx_.dgain_delay = 0;
204         ctx_.param.integration_time_apply_delay = 2;
205         ctx_.param.isp_exposure_channel_delay = 0;
206         ctx_.hdr_flag = 0;
207         break;
208     }
209     // TODO(braval) : Support other modes.
210     default:
211         return ZX_ERR_NOT_SUPPORTED;
212     }
213 
214     ctx_.param.active.width = supported_modes[mode].resolution.width;
215     ctx_.param.active.height = supported_modes[mode].resolution.height;
216     ctx_.HMAX = static_cast<uint16_t>(ReadReg(0x342) << 8 | ReadReg(0x343));
217     ctx_.VMAX = static_cast<uint16_t>(ReadReg(0x340) << 8 | ReadReg(0x341));
218     ctx_.int_max = 0x0A8C; // Max allowed for 30fps = 2782 (dec), 0x0A8E (hex)
219     ctx_.int_time_min = 1;
220     ctx_.int_time_limit = ctx_.int_max;
221     ctx_.param.total.height = ctx_.VMAX;
222     ctx_.param.total.width = ctx_.HMAX;
223     ctx_.param.pixels_per_line = ctx_.param.total.width;
224 
225     uint32_t master_clock = kMasterClock;
226     ctx_.param.lines_per_second = master_clock / ctx_.HMAX;
227 
228     ctx_.param.integration_time_min = ctx_.int_time_min;
229     ctx_.param.integration_time_limit = ctx_.int_time_limit;
230     ctx_.param.integration_time_max = ctx_.int_time_limit;
231     ctx_.param.integration_time_long_max = ctx_.int_time_limit;
232     ctx_.param.mode = mode;
233     ctx_.param.bayer = supported_modes[mode].bayer;
234     ctx_.wdr_mode = supported_modes[mode].wdr_mode;
235 
236     mipi_info_t mipi_info;
237     mipi_adap_info_t adap_info;
238 
239     mipi_info.lanes = supported_modes[mode].lanes;
240     mipi_info.ui_value = 1000 / supported_modes[mode].mbps;
241     if ((1000 % supported_modes[mode].mbps) != 0) {
242         mipi_info.ui_value += 1;
243     }
244 
245     switch (supported_modes[mode].bits) {
246     case 10:
247         adap_info.format = IMAGE_FORMAT_AM_RAW10;
248         break;
249     case 12:
250         adap_info.format = IMAGE_FORMAT_AM_RAW12;
251         break;
252     default:
253         adap_info.format = IMAGE_FORMAT_AM_RAW10;
254         break;
255     }
256 
257     adap_info.resolution.width = supported_modes[mode].resolution.width;
258     adap_info.resolution.height = supported_modes[mode].resolution.height;
259     adap_info.path = MIPI_PATH_PATH0;
260     adap_info.mode = MIPI_MODES_DDR_MODE;
261     return mipi_.Init(&mipi_info, &adap_info);
262 }
263 
StartStreaming()264 void Imx227Device::StartStreaming() {
265     ctx_.streaming_flag = 1;
266     WriteReg(0x0100, 0x01);
267 }
268 
StopStreaming()269 void Imx227Device::StopStreaming() {
270     ctx_.streaming_flag = 0;
271     WriteReg(0x0100, 0x00);
272 }
273 
SetAnalogGain(int32_t gain)274 int32_t Imx227Device::SetAnalogGain(int32_t gain) {
275     return ZX_ERR_NOT_SUPPORTED;
276 }
277 
SetDigitalGain(int32_t gain)278 int32_t Imx227Device::SetDigitalGain(int32_t gain) {
279     return ZX_ERR_NOT_SUPPORTED;
280 }
281 
SetIntegrationTime(int32_t int_time,int32_t int_time_M,int32_t int_time_L)282 void Imx227Device::SetIntegrationTime(int32_t int_time,
283                                       int32_t int_time_M,
284                                       int32_t int_time_L) {
285 }
286 
Update()287 void Imx227Device::Update() {
288 }
289 
DdkIoctl(uint32_t op,const void * in_buf,size_t in_len,void * out_buf,size_t out_len,size_t * out_actual)290 zx_status_t Imx227Device::DdkIoctl(uint32_t op, const void* in_buf, size_t in_len,
291                                    void* out_buf, size_t out_len, size_t* out_actual) {
292     switch (op) {
293     case CAMERA_IOCTL_GET_SUPPORTED_MODES: {
294         if (out_len < sizeof(fuchsia_hardware_camera_SensorMode) * MAX_SUPPORTED_MODES) {
295             return ZX_ERR_BUFFER_TOO_SMALL;
296         }
297         memcpy(out_buf, &supported_modes, sizeof(supported_modes));
298         *out_actual = sizeof(supported_modes);
299         return ZX_OK;
300     }
301 
302     default:
303         return ZX_ERR_NOT_SUPPORTED;
304     }
305 }
306 
Init(void * ctx,fidl_txn_t * txn)307 static zx_status_t Init(void* ctx, fidl_txn_t* txn) {
308     auto& self = *static_cast<Imx227Device*>(ctx);
309     zx_status_t status = self.Init();
310     return fuchsia_hardware_camera_CameraSensorInit_reply(txn, status);
311 }
312 
DeInit(void * ctx)313 static zx_status_t DeInit(void* ctx) {
314     auto& self = *static_cast<Imx227Device*>(ctx);
315     self.DeInit();
316     return ZX_OK;
317 }
318 
SetMode(void * ctx,uint8_t mode,fidl_txn_t * txn)319 static zx_status_t SetMode(void* ctx, uint8_t mode, fidl_txn_t* txn) {
320     auto& self = *static_cast<Imx227Device*>(ctx);
321     zx_status_t status = self.SetMode(mode);
322     return fuchsia_hardware_camera_CameraSensorSetMode_reply(txn, status);
323 }
324 
StartStreaming(void * ctx)325 static zx_status_t StartStreaming(void* ctx) {
326     auto& self = *static_cast<Imx227Device*>(ctx);
327     self.StartStreaming();
328     return ZX_OK;
329 }
330 
StopStreaming(void * ctx)331 static zx_status_t StopStreaming(void* ctx) {
332     auto& self = *static_cast<Imx227Device*>(ctx);
333     self.StopStreaming();
334     return ZX_OK;
335 }
336 
SetAnalogGain(void * ctx,int32_t gain,fidl_txn_t * txn)337 static zx_status_t SetAnalogGain(void* ctx, int32_t gain, fidl_txn_t* txn) {
338     auto& self = *static_cast<Imx227Device*>(ctx);
339     int32_t actual_gain = self.SetAnalogGain(gain);
340     return fuchsia_hardware_camera_CameraSensorSetAnalogGain_reply(txn, actual_gain);
341 }
342 
SetDigitalGain(void * ctx,int32_t gain,fidl_txn_t * txn)343 static zx_status_t SetDigitalGain(void* ctx, int32_t gain, fidl_txn_t* txn) {
344     auto& self = *static_cast<Imx227Device*>(ctx);
345     int32_t actual_gain = self.SetDigitalGain(gain);
346     return fuchsia_hardware_camera_CameraSensorSetDigitalGain_reply(txn, actual_gain);
347 }
348 
SetIntegrationTime(void * ctx,int32_t int_time,int32_t int_time_M,int32_t int_time_L)349 static zx_status_t SetIntegrationTime(void* ctx,
350                                       int32_t int_time,
351                                       int32_t int_time_M,
352                                       int32_t int_time_L) {
353     auto& self = *static_cast<Imx227Device*>(ctx);
354     self.SetIntegrationTime(int_time, int_time_M, int_time_L);
355     return ZX_OK;
356 }
357 
Update(void * ctx)358 static zx_status_t Update(void* ctx) {
359     auto& self = *static_cast<Imx227Device*>(ctx);
360     self.Update();
361     return ZX_OK;
362 }
363 
364 fuchsia_hardware_camera_CameraSensor_ops_t fidl_ops = {
365     .Init = Init,
366     .DeInit = DeInit,
367     .SetMode = SetMode,
368     .StartStreaming = StartStreaming,
369     .StopStreaming = StopStreaming,
370     .SetAnalogGain = SetAnalogGain,
371     .SetDigitalGain = SetDigitalGain,
372     .SetIntegrationTime = SetIntegrationTime,
373     .Update = Update,
374 };
375 
DdkMessage(fidl_msg_t * msg,fidl_txn_t * txn)376 zx_status_t Imx227Device::DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn) {
377     return fuchsia_hardware_camera_CameraSensor_dispatch(this, txn, msg, &fidl_ops);
378 }
379 
Create(zx_device_t * parent)380 zx_status_t Imx227Device::Create(zx_device_t* parent) {
381     fbl::AllocChecker ac;
382     auto sensor_device = fbl::make_unique_checked<Imx227Device>(&ac, parent);
383     if (!ac.check()) {
384         return ZX_ERR_NO_MEMORY;
385     }
386 
387     zx_status_t status = sensor_device->InitPdev(parent);
388     if (status != ZX_OK) {
389         return status;
390     }
391 
392     status = sensor_device->DdkAdd("imx227");
393 
394     // sensor_device intentionally leaked as it is now held by DevMgr.
395     __UNUSED auto ptr = sensor_device.release();
396 
397     return status;
398 }
399 
ShutDown()400 void Imx227Device::ShutDown() {
401 }
402 
DdkUnbind()403 void Imx227Device::DdkUnbind() {
404     DdkRemove();
405 }
406 
DdkRelease()407 void Imx227Device::DdkRelease() {
408     ShutDown();
409     delete this;
410 }
411 
412 } // namespace camera
413 
imx227_bind(void * ctx,zx_device_t * device)414 extern "C" zx_status_t imx227_bind(void* ctx, zx_device_t* device) {
415     return camera::Imx227Device::Create(device);
416 }
417