m5mols_core.c revision b25b895805dd415f218cfd4892d17aeb2db425f7
1bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/* 2bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * Driver for M-5MOLS 8M Pixel camera sensor with ISP 3bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 4bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * Copyright (C) 2011 Samsung Electronics Co., Ltd. 5c30701130cf7bff4f97a148b1bc96f878c046a40HeungJun, Kim * Author: HeungJun Kim <riverful.kim@samsung.com> 6bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 7bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * Copyright (C) 2009 Samsung Electronics Co., Ltd. 8c30701130cf7bff4f97a148b1bc96f878c046a40HeungJun, Kim * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> 9bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 10bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * This program is free software; you can redistribute it and/or modify 11bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * it under the terms of the GNU General Public License as published by 12bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * the Free Software Foundation; either version 2 of the License, or 13bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * (at your option) any later version. 14bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 15bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 16bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include <linux/i2c.h> 17bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include <linux/slab.h> 18bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include <linux/irq.h> 19bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include <linux/interrupt.h> 20bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include <linux/delay.h> 21bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include <linux/gpio.h> 22bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include <linux/regulator/consumer.h> 23bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include <linux/videodev2.h> 247a707b89202f905bd9f9fbde326933c59a81214cPaul Gortmaker#include <linux/module.h> 25bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include <media/v4l2-ctrls.h> 26bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include <media/v4l2-device.h> 27bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include <media/v4l2-subdev.h> 28bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include <media/m5mols.h> 29bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 30bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include "m5mols.h" 31bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#include "m5mols_reg.h" 32bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 33bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimint m5mols_debug; 34bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimmodule_param(m5mols_debug, int, 0644); 35bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 36bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#define MODULE_NAME "M5MOLS" 37bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#define M5MOLS_I2C_CHECK_RETRY 500 38bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 39bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/* The regulator consumer names for external voltage regulators */ 40bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic struct regulator_bulk_data supplies[] = { 41bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 42bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .supply = "core", /* ARM core power, 1.2V */ 43bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim }, { 44bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .supply = "dig_18", /* digital power 1, 1.8V */ 45bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim }, { 46bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .supply = "d_sensor", /* sensor power 1, 1.8V */ 47bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim }, { 48bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .supply = "dig_28", /* digital power 2, 2.8V */ 49bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim }, { 50bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .supply = "a_sensor", /* analog power */ 51bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim }, { 52bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .supply = "dig_12", /* digital power 3, 1.2V */ 53bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim }, 54bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 55bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 56bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = { 57bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim [M5MOLS_RESTYPE_MONITOR] = { 58bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .width = 1920, 59bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .height = 1080, 60bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .code = V4L2_MBUS_FMT_VYUY8_2X8, 61bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .field = V4L2_FIELD_NONE, 62bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .colorspace = V4L2_COLORSPACE_JPEG, 63bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim }, 64bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim [M5MOLS_RESTYPE_CAPTURE] = { 65bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .width = 1920, 66bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .height = 1080, 67bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .code = V4L2_MBUS_FMT_JPEG_1X8, 68bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .field = V4L2_FIELD_NONE, 69bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .colorspace = V4L2_COLORSPACE_JPEG, 70bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim }, 71bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 72bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim#define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt) 73bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 74bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic const struct m5mols_resolution m5mols_reg_res[] = { 75bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */ 76bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */ 77bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */ 78bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 }, 79bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* QVGA */ 80bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */ 81bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* WQVGA */ 82bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */ 83bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */ 84bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 }, 85bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */ 86bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */ 87bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 }, 88bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */ 89bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */ 90bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */ 91bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */ 92bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 2.63fps 8M */ 93bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */ 94bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 95bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */ 96bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */ 97bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 }, 98bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */ 99bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */ 100bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */ 101bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */ 102bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */ 103bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */ 104bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */ 105bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3Mega */ 106bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 }, 107bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4Mega */ 108bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 }, 109bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5Mega */ 110bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6Mega */ 111bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 }, 112bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8Mega */ 113bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 114bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 115bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 116bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * m5mols_swap_byte - an byte array to integer conversion function 117bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * @size: size in bytes of I2C packet defined in the M-5MOLS datasheet 118bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 119bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * Convert I2C data byte array with performing any required byte 120bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * reordering to assure proper values for each data type, regardless 121bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * of the architecture endianness. 122bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 123bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic u32 m5mols_swap_byte(u8 *data, u8 length) 124bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 125bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (length == 1) 126bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return *data; 127bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim else if (length == 2) 128bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return be16_to_cpu(*((u16 *)data)); 129bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim else 130bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return be32_to_cpu(*((u32 *)data)); 131bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 132bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 133bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 134bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * m5mols_read - I2C read function 135bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * @reg: combination of size, category and command for the I2C packet 13657644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim * @size: desired size of I2C packet 137bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * @val: read value 1380f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim * 1390f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim * Returns 0 on success, or else negative errno. 140bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 14157644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kimstatic int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val) 142bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 143bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct i2c_client *client = v4l2_get_subdevdata(sd); 1440f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim struct m5mols_info *info = to_m5mols(sd); 145bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; 146bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim u8 category = I2C_CATEGORY(reg); 147bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim u8 cmd = I2C_COMMAND(reg); 148bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct i2c_msg msg[2]; 149bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim u8 wbuf[5]; 150bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 151bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 152bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!client->adapter) 153bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -ENODEV; 154bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 155bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim msg[0].addr = client->addr; 156bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim msg[0].flags = 0; 157bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim msg[0].len = 5; 158bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim msg[0].buf = wbuf; 159bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim wbuf[0] = 5; 160bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim wbuf[1] = M5MOLS_BYTE_READ; 161bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim wbuf[2] = category; 162bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim wbuf[3] = cmd; 163bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim wbuf[4] = size; 164bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 165bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim msg[1].addr = client->addr; 166bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim msg[1].flags = I2C_M_RD; 167bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim msg[1].len = size + 1; 168bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim msg[1].buf = rbuf; 169bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 170bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim /* minimum stabilization time */ 171bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim usleep_range(200, 200); 172bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 173bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = i2c_transfer(client->adapter, msg, 2); 1740f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim 1750f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim if (ret == 2) { 1760f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim *val = m5mols_swap_byte(&rbuf[1], size); 1770f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim return 0; 178bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 179bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 1800f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim if (info->isp_ready) 1810f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n", 1820f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim size, category, cmd, ret); 183bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 1840f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim return ret < 0 ? ret : -EIO; 185bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 186bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 18757644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kimint m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val) 18857644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim{ 18957644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim u32 val_32; 19057644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim int ret; 19157644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim 19257644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim if (I2C_SIZE(reg) != 1) { 19357644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim v4l2_err(sd, "Wrong data size\n"); 19457644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim return -EINVAL; 19557644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim } 19657644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim 19757644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); 19857644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim if (ret) 19957644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim return ret; 20057644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim 20157644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim *val = (u8)val_32; 20257644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim return ret; 20357644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim} 20457644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim 20557644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kimint m5mols_read_u16(struct v4l2_subdev *sd, u32 reg, u16 *val) 20657644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim{ 20757644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim u32 val_32; 20857644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim int ret; 20957644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim 21057644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim if (I2C_SIZE(reg) != 2) { 21157644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim v4l2_err(sd, "Wrong data size\n"); 21257644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim return -EINVAL; 21357644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim } 21457644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim 21557644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); 21657644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim if (ret) 21757644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim return ret; 21857644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim 21957644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim *val = (u16)val_32; 22057644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim return ret; 22157644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim} 22257644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim 22357644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kimint m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val) 22457644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim{ 22557644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim if (I2C_SIZE(reg) != 4) { 22657644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim v4l2_err(sd, "Wrong data size\n"); 22757644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim return -EINVAL; 22857644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim } 22957644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim 23057644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim return m5mols_read(sd, I2C_SIZE(reg), reg, val); 23157644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim} 23257644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim 233bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 234bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * m5mols_write - I2C command write function 235bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * @reg: combination of size, category and command for the I2C packet 236bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * @val: value to write 2370f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim * 2380f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim * Returns 0 on success, or else negative errno. 239bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 240bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimint m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) 241bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 242bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct i2c_client *client = v4l2_get_subdevdata(sd); 2430f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim struct m5mols_info *info = to_m5mols(sd); 244bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4]; 245bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim u8 category = I2C_CATEGORY(reg); 246bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim u8 cmd = I2C_COMMAND(reg); 247bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim u8 size = I2C_SIZE(reg); 248bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim u32 *buf = (u32 *)&wbuf[4]; 249bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct i2c_msg msg[1]; 250bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 251bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 252bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!client->adapter) 253bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -ENODEV; 254bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 255bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (size != 1 && size != 2 && size != 4) { 256bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_err(sd, "Wrong data size\n"); 257bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -EINVAL; 258bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 259bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 260bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim msg->addr = client->addr; 261bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim msg->flags = 0; 262bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim msg->len = (u16)size + 4; 263bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim msg->buf = wbuf; 264bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim wbuf[0] = size + 4; 265bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim wbuf[1] = M5MOLS_BYTE_WRITE; 266bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim wbuf[2] = category; 267bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim wbuf[3] = cmd; 268bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 269bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim *buf = m5mols_swap_byte((u8 *)&val, size); 270bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 271bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim usleep_range(200, 200); 272bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 273bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = i2c_transfer(client->adapter, msg, 1); 2740f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim if (ret == 1) 2750f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim return 0; 276bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 2770f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim if (info->isp_ready) 2780f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim v4l2_err(sd, "write failed: cat:%02x cmd:%02x ret:%d\n", 2790f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim category, cmd, ret); 2800f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim 2810f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim return ret < 0 ? ret : -EIO; 282bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 283bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 284575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim/** 285575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim * m5mols_busy_wait - Busy waiting with I2C register polling 286575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim * @reg: the I2C_REG() address of an 8-bit status register to check 287575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim * @value: expected status register value 288575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim * @mask: bit mask for the read status register value 289575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim * @timeout: timeout in miliseconds, or -1 for default timeout 290575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim * 291575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim * The @reg register value is ORed with @mask before comparing with @value. 292575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim * 293575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim * Return: 0 if the requested condition became true within less than 294575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim * @timeout ms, or else negative errno. 295575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim */ 296575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kimint m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask, 297575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim int timeout) 298bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 299575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim int ms = timeout < 0 ? M5MOLS_BUSY_WAIT_DEF_TIMEOUT : timeout; 300575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim unsigned long end = jiffies + msecs_to_jiffies(ms); 301575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim u8 status; 302bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 303575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim do { 304575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim int ret = m5mols_read_u8(sd, reg, &status); 305575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim 306575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim if (ret < 0 && !(mask & M5MOLS_I2C_RDY_WAIT_FL)) 307bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 308575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim if (!ret && (status & mask & 0xff) == (value & 0xff)) 309bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 310575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim usleep_range(100, 250); 311575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim } while (ms > 0 && time_is_after_jiffies(end)); 312575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim 313bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -EBUSY; 314bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 315bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 316bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 317bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts 318bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 319bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * Before writing desired interrupt value the INT_FACTOR register should 320bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * be read to clear pending interrupts. 321bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 32257644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kimint m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg) 323bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 324bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info = to_m5mols(sd); 32557644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim u8 mask = is_available_af(info) ? REG_INT_AF : 0; 32657644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim u8 dummy; 327bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 328bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 32957644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy); 330bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 331bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask); 332bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 333bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 334bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 335ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kimint m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout) 336ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim{ 337ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim struct m5mols_info *info = to_m5mols(sd); 338ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim 339ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim int ret = wait_event_interruptible_timeout(info->irq_waitq, 340ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim atomic_add_unless(&info->irq_done, -1, 0), 341ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim msecs_to_jiffies(timeout)); 342ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim if (ret <= 0) 343ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim return ret ? ret : -ETIMEDOUT; 344ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim 345ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask, 346ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1); 347ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim} 348ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim 349bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 350bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * m5mols_reg_mode - Write the mode and check busy status 351bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 352bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * It always accompanies a little delay changing the M-5MOLS mode, so it is 353bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * needed checking current busy status to guarantee right mode. 354bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 35557644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kimstatic int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode) 356bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 357bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); 358575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim if (ret < 0) 359575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim return ret; 360575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim return m5mols_busy_wait(sd, SYSTEM_SYSMODE, mode, 0xff, 361575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim M5MOLS_MODE_CHANGE_TIMEOUT); 362bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 363bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 364bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 3653c5da0baaada8e8c7176a3e310dfdb4362f74d80Sylwester Nawrocki * m5mols_set_mode - set the M-5MOLS controller mode 366bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * @mode: the required operation mode 367bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 368bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * The commands of M-5MOLS are grouped into specific modes. Each functionality 3693c5da0baaada8e8c7176a3e310dfdb4362f74d80Sylwester Nawrocki * can be guaranteed only when the sensor is operating in mode which a command 3703c5da0baaada8e8c7176a3e310dfdb4362f74d80Sylwester Nawrocki * belongs to. 371bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 3723c5da0baaada8e8c7176a3e310dfdb4362f74d80Sylwester Nawrockiint m5mols_set_mode(struct m5mols_info *info, u8 mode) 373bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 374bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev *sd = &info->sd; 375bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret = -EINVAL; 37657644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim u8 reg; 377bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 378a32390d808b5b7a6b1c7f9236673c917b4733f13Thomas Jarosch if (mode < REG_PARAMETER || mode > REG_CAPTURE) 379bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 380bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 38157644f56234a154afffd0f4d53becf8ff4a55b41HeungJun, Kim ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®); 382630caa23b75ca5d399791fa5a4d8d5f4adf81489Sylwester Nawrocki if (ret || reg == mode) 383bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 384bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 385bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim switch (reg) { 386bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim case REG_PARAMETER: 387bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_reg_mode(sd, REG_MONITOR); 388630caa23b75ca5d399791fa5a4d8d5f4adf81489Sylwester Nawrocki if (mode == REG_MONITOR) 389bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim break; 390bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 391bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_reg_mode(sd, REG_CAPTURE); 392bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim break; 393bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 394bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim case REG_MONITOR: 395bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (mode == REG_PARAMETER) { 396bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_reg_mode(sd, REG_PARAMETER); 397bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim break; 398bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 399bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 400bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_reg_mode(sd, REG_CAPTURE); 401bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim break; 402bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 403bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim case REG_CAPTURE: 404bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_reg_mode(sd, REG_MONITOR); 405630caa23b75ca5d399791fa5a4d8d5f4adf81489Sylwester Nawrocki if (mode == REG_MONITOR) 406bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim break; 407bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 408bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_reg_mode(sd, REG_PARAMETER); 409bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim break; 410bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 411bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim default: 412bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_warn(sd, "Wrong mode: %d\n", mode); 413bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 414bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 415bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 416bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->mode = mode; 417bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 418bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 419bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 420bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 421bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 422bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * m5mols_get_version - retrieve full revisions information of M-5MOLS 423bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 424bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * The version information includes revisions of hardware and firmware, 425bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * AutoFocus alghorithm version and the version string. 426bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 427bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_get_version(struct v4l2_subdev *sd) 428bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 429bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info = to_m5mols(sd); 430a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim struct m5mols_version *ver = &info->ver; 431a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim u8 *str = ver->str; 432a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim int i; 433bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 434bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 435a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer); 436a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim if (!ret) 437a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project); 438a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim if (!ret) 439a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw); 440a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim if (!ret) 441a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw); 442a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim if (!ret) 443a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param); 444a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim if (!ret) 445a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim ret = m5mols_read_u16(sd, SYSTEM_VER_AWB, &ver->awb); 446a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim if (!ret) 447a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim ret = m5mols_read_u8(sd, AF_VERSION, &ver->af); 448a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim if (ret) 449a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim return ret; 450bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 451a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim for (i = 0; i < VERSION_STRING_SIZE; i++) { 452a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]); 453bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) 454bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 455a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim } 456bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 457a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim ver->fw = be16_to_cpu(ver->fw); 458a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim ver->hw = be16_to_cpu(ver->hw); 459a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim ver->param = be16_to_cpu(ver->param); 460a6354d2e5da646926ce492b66b527a1efc39cd27HeungJun, Kim ver->awb = be16_to_cpu(ver->awb); 461bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 462bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_info(sd, "Manufacturer\t[%s]\n", 463bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? 464bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim "Samsung Electro-Machanics" : 465bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 466bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim "Samsung Fiber-Optics" : 467bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim is_manufacturer(info, REG_SAMSUNG_TECHWIN) ? 468bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim "Samsung Techwin" : "None"); 469bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n", 470bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->ver.customer, info->ver.project); 471bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 472bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!is_available_af(info)) 473bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_info(sd, "No support Auto Focus on this firmware\n"); 474bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 475bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 476bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 477bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 478bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 479bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * __find_restype - Lookup M-5MOLS resolution type according to pixel code 480bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * @code: pixel code 481bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 482bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code) 483bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 484bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR; 485bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 486bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim do { 487bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (code == m5mols_default_ffmt[type].code) 488bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return type; 489bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } while (type++ != SIZE_DEFAULT_FFMT); 490bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 491bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 492bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 493bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 494bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 495bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * __find_resolution - Lookup preset and type of M-5MOLS's resolution 496bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * @mf: pixel format to find/negotiate the resolution preset for 497bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * @type: M-5MOLS resolution type 498bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * @resolution: M-5MOLS resolution preset register value 499bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 500bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * Find nearest resolution matching resolution preset and adjust mf 501bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * to supported values. 502bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 503bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int __find_resolution(struct v4l2_subdev *sd, 504bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_mbus_framefmt *mf, 505bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim enum m5mols_restype *type, 506bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim u32 *resolution) 507bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 508bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim const struct m5mols_resolution *fsize = &m5mols_reg_res[0]; 509bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim const struct m5mols_resolution *match = NULL; 510bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim enum m5mols_restype stype = __find_restype(mf->code); 511bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int i = ARRAY_SIZE(m5mols_reg_res); 512bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim unsigned int min_err = ~0; 513bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 514bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim while (i--) { 515bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int err; 516bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (stype == fsize->type) { 517bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim err = abs(fsize->width - mf->width) 518bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim + abs(fsize->height - mf->height); 519bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 520bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (err < min_err) { 521bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim min_err = err; 522bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim match = fsize; 523bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 524bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 525bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim fsize++; 526bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 527bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (match) { 528bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim mf->width = match->width; 529bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim mf->height = match->height; 530bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim *resolution = match->reg; 531bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim *type = stype; 532bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 533bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 534bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 535bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -EINVAL; 536bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 537bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 538bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info, 539bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev_fh *fh, 540bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim enum v4l2_subdev_format_whence which, 541bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim enum m5mols_restype type) 542bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 543bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (which == V4L2_SUBDEV_FORMAT_TRY) 544bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; 545bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 546bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return &info->ffmt[type]; 547bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 548bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 549bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 550bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev_format *fmt) 551bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 552bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info = to_m5mols(sd); 553bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_mbus_framefmt *format; 554bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 555bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim format = __find_format(info, fh, fmt->which, info->res_type); 556bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!format) 557bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -EINVAL; 558bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 559bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim fmt->format = *format; 560bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 561bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 562bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 563bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 564bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev_format *fmt) 565bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 566bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info = to_m5mols(sd); 567bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_mbus_framefmt *format = &fmt->format; 568bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_mbus_framefmt *sfmt; 569bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim enum m5mols_restype type; 570bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim u32 resolution = 0; 571bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 572bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 573bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = __find_resolution(sd, format, &type, &resolution); 574bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret < 0) 575bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 576bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 577bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim sfmt = __find_format(info, fh, fmt->which, type); 578bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!sfmt) 579bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 580bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 581fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki 582fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki format->code = m5mols_default_ffmt[type].code; 583fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki format->colorspace = V4L2_COLORSPACE_JPEG; 584fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki format->field = V4L2_FIELD_NONE; 585bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 586bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 587fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki *sfmt = *format; 588bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->resolution = resolution; 589bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->res_type = type; 590bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 591bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 592bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 593bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 594bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 595bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_enum_mbus_code(struct v4l2_subdev *sd, 596bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev_fh *fh, 597bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev_mbus_code_enum *code) 598bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 599bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!code || code->index >= SIZE_DEFAULT_FFMT) 600bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -EINVAL; 601bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 602bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim code->code = m5mols_default_ffmt[code->index].code; 603bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 604bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 605bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 606bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 607bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic struct v4l2_subdev_pad_ops m5mols_pad_ops = { 608bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .enum_mbus_code = m5mols_enum_mbus_code, 609bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .get_fmt = m5mols_get_fmt, 610bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .set_fmt = m5mols_set_fmt, 611bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 612bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 613bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 6145d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki * m5mols_restore_controls - Apply current control values to the registers 615bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 6165d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki * m5mols_do_scenemode() handles all parameters for which there is yet no 6175d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki * individual control. It should be replaced at some point by setting each 6185d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki * control individually, in required register set up order. 619bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 6205d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrockiint m5mols_restore_controls(struct m5mols_info *info) 621bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 6225d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki int ret; 623bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 6245d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki if (info->ctrl_sync) 6255d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki return 0; 626bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 6275d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); 6285d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki if (ret) 6295d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki return ret; 6305d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki 6315d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki ret = v4l2_ctrl_handler_setup(&info->handle); 6325d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki info->ctrl_sync = !ret; 633bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 634bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 635bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 636bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 637bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 638bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * m5mols_start_monitor - Start the monitor mode 639bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 640bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * Before applying the controls setup the resolution and frame rate 641bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * in PARAMETER mode, and then switch over to MONITOR mode. 642bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 643bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_start_monitor(struct m5mols_info *info) 644bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 645bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev *sd = &info->sd; 646bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 647bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 6483c5da0baaada8e8c7176a3e310dfdb4362f74d80Sylwester Nawrocki ret = m5mols_set_mode(info, REG_PARAMETER); 649bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 650bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution); 651bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 652bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30); 653bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 6543c5da0baaada8e8c7176a3e310dfdb4362f74d80Sylwester Nawrocki ret = m5mols_set_mode(info, REG_MONITOR); 655bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 6565d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki ret = m5mols_restore_controls(info); 657bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 658bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 659bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 660bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 661bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_s_stream(struct v4l2_subdev *sd, int enable) 662bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 663bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info = to_m5mols(sd); 664fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki u32 code = info->ffmt[info->res_type].code; 665bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 666bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (enable) { 667bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret = -EINVAL; 668bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 669fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki if (is_code(code, M5MOLS_RESTYPE_MONITOR)) 670bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_start_monitor(info); 671fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki if (is_code(code, M5MOLS_RESTYPE_CAPTURE)) 672bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_start_capture(info); 673bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 674bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 675bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 676bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 6773c5da0baaada8e8c7176a3e310dfdb4362f74d80Sylwester Nawrocki return m5mols_set_mode(info, REG_PARAMETER); 678bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 679bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 680bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic const struct v4l2_subdev_video_ops m5mols_video_ops = { 681bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .s_stream = m5mols_s_stream, 682bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 683bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 684bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_sensor_power(struct m5mols_info *info, bool enable) 685bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 686bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev *sd = &info->sd; 687bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct i2c_client *client = v4l2_get_subdevdata(sd); 688bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim const struct m5mols_platform_data *pdata = info->pdata; 689bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 690bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 6910f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim if (info->power == enable) 6920f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim return 0; 693bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 6940f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim if (enable) { 695bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (info->set_power) { 696bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = info->set_power(&client->dev, 1); 697bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) 698bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 699bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 700bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 701bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); 702bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) { 703bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->set_power(&client->dev, 0); 704bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 705bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 706bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 707bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity); 7080f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim info->power = 1; 709bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 710bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 711bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 712bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 713bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); 714bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) 715bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 716bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 717bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (info->set_power) 718bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->set_power(&client->dev, 0); 719bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 720bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim gpio_set_value(pdata->gpio_reset, pdata->reset_polarity); 7210f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim 7220f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim info->isp_ready = 0; 7230f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim info->power = 0; 724bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 725bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 726bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 727bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 728bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/* m5mols_update_fw - optional firmware update routine */ 729bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimint __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd, 730bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int (*set_power)(struct m5mols_info *, bool)) 731bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 732bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 733bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 734bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 735bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 7360f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim * m5mols_fw_start - M-5MOLS internal ARM controller initialization 737bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 7380f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim * Execute the M-5MOLS internal ARM controller initialization sequence. 7390f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim * This function should be called after the supply voltage has been 7400f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim * applied and before any requests to the device are made. 741bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 7420f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kimstatic int m5mols_fw_start(struct v4l2_subdev *sd) 743bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 7440f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim struct m5mols_info *info = to_m5mols(sd); 745bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 746bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 7470f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim atomic_set(&info->irq_done, 0); 7480f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim /* Wait until I2C slave is initialized in Flash Writer mode */ 7490f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim ret = m5mols_busy_wait(sd, FLASH_CAM_START, REG_IN_FLASH_MODE, 7500f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim M5MOLS_I2C_RDY_WAIT_FL | 0xff, -1); 7510f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim if (!ret) 7520f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); 7530f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim if (!ret) 7540f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim ret = m5mols_wait_interrupt(sd, REG_INT_MODE, 2000); 755bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret < 0) 756bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 757bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 7580f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim info->isp_ready = 1; 759bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 760bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_get_version(sd); 761bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 762bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_update_fw(sd, m5mols_sensor_power); 763bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) 764bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 765bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 766bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n"); 767bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 768bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI); 769bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 77092e93a1fd065c8dfa592b01d3cb681e83bfc98ebHeungJun Kim ret = m5mols_enable_interrupt(sd, 77192e93a1fd065c8dfa592b01d3cb681e83bfc98ebHeungJun Kim REG_INT_AF | REG_INT_CAPTURE); 772bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 773bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 774bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 775bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 776bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 777bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * m5mols_s_power - Main sensor power control function 778bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 779bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * To prevent breaking the lens when the sensor is powered off the Soft-Landing 780bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * algorithm is called where available. The Soft-Landing algorithm availability 781bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * dependends on the firmware provider. 782bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 783bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_s_power(struct v4l2_subdev *sd, int on) 784bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 785bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info = to_m5mols(sd); 786bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 787bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 788bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (on) { 789bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_sensor_power(info, true); 790bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 7910f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim ret = m5mols_fw_start(sd); 792bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 793bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 794bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 795bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { 7963c5da0baaada8e8c7176a3e310dfdb4362f74d80Sylwester Nawrocki ret = m5mols_set_mode(info, REG_MONITOR); 797bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 798bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP); 799bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 800bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF); 801bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 802575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim ret = m5mols_busy_wait(sd, SYSTEM_STATUS, REG_AF_IDLE, 803575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim 0xff, -1); 804575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim if (ret < 0) 805575d6252a715c599964ec6ec06428e6362c0633eHeungJun Kim v4l2_warn(sd, "Soft landing lens failed\n"); 806bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 807bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 808bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_sensor_power(info, false); 809aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki info->ctrl_sync = 0; 810bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 811bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 812bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 813bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 814bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_log_status(struct v4l2_subdev *sd) 815bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 816bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info = to_m5mols(sd); 817bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 818bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_ctrl_handler_log_status(&info->handle, sd->name); 819bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 820bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 821bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 822bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 823bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic const struct v4l2_subdev_core_ops m5mols_core_ops = { 824bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .s_power = m5mols_s_power, 825bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .g_ctrl = v4l2_subdev_g_ctrl, 826bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .s_ctrl = v4l2_subdev_s_ctrl, 827bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .queryctrl = v4l2_subdev_queryctrl, 828bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .querymenu = v4l2_subdev_querymenu, 829bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, 830bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, 831bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, 832bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .log_status = m5mols_log_status, 833bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 834bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 835aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki/* 836aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki * V4L2 subdev internal operations 837aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki */ 838aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrockistatic int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 839aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki{ 840aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); 841aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki 842aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki *format = m5mols_default_ffmt[0]; 843aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki return 0; 844aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki} 845aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki 846aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrockistatic const struct v4l2_subdev_internal_ops m5mols_subdev_internal_ops = { 847aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki .open = m5mols_open, 848aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki}; 849aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki 850bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic const struct v4l2_subdev_ops m5mols_ops = { 851bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .core = &m5mols_core_ops, 852bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .pad = &m5mols_pad_ops, 853bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .video = &m5mols_video_ops, 854bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 855bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 856bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic irqreturn_t m5mols_irq_handler(int irq, void *data) 857bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 858ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim struct m5mols_info *info = to_m5mols(data); 859bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 860ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim atomic_set(&info->irq_done, 1); 861ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim wake_up_interruptible(&info->irq_waitq); 862bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 863bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return IRQ_HANDLED; 864bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 865bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 866bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int __devinit m5mols_probe(struct i2c_client *client, 867bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim const struct i2c_device_id *id) 868bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 869bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim const struct m5mols_platform_data *pdata = client->dev.platform_data; 870bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info; 871bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev *sd; 872bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 873bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 874bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (pdata == NULL) { 875bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim dev_err(&client->dev, "No platform data\n"); 876bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -EINVAL; 877bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 878bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 879bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!gpio_is_valid(pdata->gpio_reset)) { 880bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim dev_err(&client->dev, "No valid RESET GPIO specified\n"); 881bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -EINVAL; 882bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 883bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 8845b3bdfce675040b65a8b97f8209d78a31935c48fSylwester Nawrocki if (!client->irq) { 885bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim dev_err(&client->dev, "Interrupt not assigned\n"); 886bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -EINVAL; 887bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 888bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 889bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL); 890bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!info) 891bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -ENOMEM; 892bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 893bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->pdata = pdata; 894bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->set_power = pdata->set_power; 895bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 896bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST"); 897bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) { 898bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim dev_err(&client->dev, "Failed to request gpio: %d\n", ret); 899bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim goto out_free; 900bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 901bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity); 902bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 903bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies); 904bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) { 905bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim dev_err(&client->dev, "Failed to get regulators: %d\n", ret); 906bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim goto out_gpio; 907bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 908bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 909bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim sd = &info->sd; 910bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_i2c_subdev_init(sd, client, &m5mols_ops); 911c5024a70bb60b678f08586ed786340ec162d250fSylwester Nawrocki strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); 91287eaec5dff4e20228fb6ac72dc849fd12f4e86beSylwester Nawrocki sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 913bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 914aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki sd->internal_ops = &m5mols_subdev_internal_ops; 915bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->pad.flags = MEDIA_PAD_FL_SOURCE; 916bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = media_entity_init(&sd->entity, 1, &info->pad, 0); 917bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret < 0) 918bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim goto out_reg; 919bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; 920bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 921bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim init_waitqueue_head(&info->irq_waitq); 9225b3bdfce675040b65a8b97f8209d78a31935c48fSylwester Nawrocki ret = request_irq(client->irq, m5mols_irq_handler, 923bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim IRQF_TRIGGER_RISING, MODULE_NAME, sd); 924bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) { 925bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim dev_err(&client->dev, "Interrupt request failed: %d\n", ret); 926bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim goto out_me; 927bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 928bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->res_type = M5MOLS_RESTYPE_MONITOR; 929f428948b98e3b9476057ee483e7e763a5ac61a69Sylwester Nawrocki info->ffmt[0] = m5mols_default_ffmt[0]; 930f428948b98e3b9476057ee483e7e763a5ac61a69Sylwester Nawrocki info->ffmt[1] = m5mols_default_ffmt[1]; 931ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim 932aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki ret = m5mols_sensor_power(info, true); 933aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki if (ret) 934aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki goto out_me; 935aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki 936aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki ret = m5mols_fw_start(sd); 937aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki if (!ret) 9383c5da0baaada8e8c7176a3e310dfdb4362f74d80Sylwester Nawrocki ret = m5mols_init_controls(sd); 939aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki 940b25b895805dd415f218cfd4892d17aeb2db425f7Julia Lawall ret = m5mols_sensor_power(info, false); 941aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki if (!ret) 942aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki return 0; 943bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimout_me: 944bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim media_entity_cleanup(&sd->entity); 945bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimout_reg: 946bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim regulator_bulk_free(ARRAY_SIZE(supplies), supplies); 947bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimout_gpio: 948bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim gpio_free(pdata->gpio_reset); 949bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimout_free: 950bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim kfree(info); 951bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 952bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 953bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 954bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int __devexit m5mols_remove(struct i2c_client *client) 955bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 956bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev *sd = i2c_get_clientdata(client); 957bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info = to_m5mols(sd); 958bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 959bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_device_unregister_subdev(sd); 960aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki v4l2_ctrl_handler_free(sd->ctrl_handler); 9615b3bdfce675040b65a8b97f8209d78a31935c48fSylwester Nawrocki free_irq(client->irq, sd); 962bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 963bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim regulator_bulk_free(ARRAY_SIZE(supplies), supplies); 964bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim gpio_free(info->pdata->gpio_reset); 965bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim media_entity_cleanup(&sd->entity); 966bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim kfree(info); 967bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 968bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 969bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 970bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic const struct i2c_device_id m5mols_id[] = { 971bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { MODULE_NAME, 0 }, 972bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { }, 973bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 974bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, KimMODULE_DEVICE_TABLE(i2c, m5mols_id); 975bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 976bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic struct i2c_driver m5mols_i2c_driver = { 977bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .driver = { 978bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .name = MODULE_NAME, 979bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim }, 980bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .probe = m5mols_probe, 981bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .remove = __devexit_p(m5mols_remove), 982bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .id_table = m5mols_id, 983bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 984bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 985c6e8d86fffd8edf1bfccbd441b1812ee919fe3d5Axel Linmodule_i2c_driver(m5mols_i2c_driver); 986bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 987bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, KimMODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>"); 988bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, KimMODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>"); 989bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, KimMODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver"); 990bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, KimMODULE_LICENSE("GPL"); 991