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; 5545565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki int ret = 0; 5555565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki 5565565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki mutex_lock(&info->lock); 557bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 558bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim format = __find_format(info, fh, fmt->which, info->res_type); 55912861dc659c7181e0b52facd97df70c6dd326106Sylwester Nawrocki if (format) 5605565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki fmt->format = *format; 5615565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki else 5625565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki ret = -EINVAL; 563bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 5645565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki mutex_unlock(&info->lock); 5655565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki return ret; 566bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 567bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 568bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 569bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev_format *fmt) 570bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 571bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info = to_m5mols(sd); 572bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_mbus_framefmt *format = &fmt->format; 573bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_mbus_framefmt *sfmt; 574bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim enum m5mols_restype type; 575bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim u32 resolution = 0; 576bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 577bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 578bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = __find_resolution(sd, format, &type, &resolution); 579bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret < 0) 580bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 581bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 582bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim sfmt = __find_format(info, fh, fmt->which, type); 583bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!sfmt) 584bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 585bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 5865565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki mutex_lock(&info->lock); 587fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki 588fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki format->code = m5mols_default_ffmt[type].code; 589fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki format->colorspace = V4L2_COLORSPACE_JPEG; 590fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki format->field = V4L2_FIELD_NONE; 591bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 592bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 593fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki *sfmt = *format; 594bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->resolution = resolution; 595bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->res_type = type; 596bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 597bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 5985565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki mutex_unlock(&info->lock); 5995565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki return ret; 600bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 601bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 602ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrockistatic int m5mols_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, 603ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki struct v4l2_mbus_frame_desc *fd) 604ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki{ 605ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki struct m5mols_info *info = to_m5mols(sd); 606ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki 607ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki if (pad != 0 || fd == NULL) 608ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki return -EINVAL; 609ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki 610ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki mutex_lock(&info->lock); 611ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki /* 612ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki * .get_frame_desc is only used for compressed formats, 613ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki * thus we always return the capture frame parameters here. 614ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki */ 615ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki fd->entry[0].length = info->cap.buf_size; 616ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki fd->entry[0].pixelcode = info->ffmt[M5MOLS_RESTYPE_CAPTURE].code; 617ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki mutex_unlock(&info->lock); 618ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki 619ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki fd->entry[0].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; 620ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki fd->num_entries = 1; 621ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki 622ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki return 0; 623ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki} 624ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki 625ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrockistatic int m5mols_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad, 626ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki struct v4l2_mbus_frame_desc *fd) 627ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki{ 628ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki struct m5mols_info *info = to_m5mols(sd); 629ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki struct v4l2_mbus_framefmt *mf = &info->ffmt[M5MOLS_RESTYPE_CAPTURE]; 630ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki 631ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki if (pad != 0 || fd == NULL) 632ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki return -EINVAL; 633ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki 634ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki fd->entry[0].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; 635ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki fd->num_entries = 1; 636ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki fd->entry[0].length = clamp_t(u32, fd->entry[0].length, 637ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki mf->width * mf->height, 638ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki M5MOLS_MAIN_JPEG_SIZE_MAX); 639ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki mutex_lock(&info->lock); 640ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki info->cap.buf_size = fd->entry[0].length; 641ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki mutex_unlock(&info->lock); 642ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki 643ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki return 0; 644ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki} 645ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki 646ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki 647bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_enum_mbus_code(struct v4l2_subdev *sd, 648bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev_fh *fh, 649bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev_mbus_code_enum *code) 650bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 651bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!code || code->index >= SIZE_DEFAULT_FFMT) 652bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -EINVAL; 653bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 654bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim code->code = m5mols_default_ffmt[code->index].code; 655bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 656bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 657bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 658bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 659bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic struct v4l2_subdev_pad_ops m5mols_pad_ops = { 660bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .enum_mbus_code = m5mols_enum_mbus_code, 661bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .get_fmt = m5mols_get_fmt, 662bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .set_fmt = m5mols_set_fmt, 663ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki .get_frame_desc = m5mols_get_frame_desc, 664ab7ef22419927910e563170db41f0a428d20b0a2Sylwester Nawrocki .set_frame_desc = m5mols_set_frame_desc, 665bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 666bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 667bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 6685d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki * m5mols_restore_controls - Apply current control values to the registers 669bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 6705d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki * m5mols_do_scenemode() handles all parameters for which there is yet no 6715d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki * individual control. It should be replaced at some point by setting each 6725d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki * control individually, in required register set up order. 673bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 6745d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrockiint m5mols_restore_controls(struct m5mols_info *info) 675bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 6765d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki int ret; 677bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 6785d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki if (info->ctrl_sync) 6795d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki return 0; 680bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 6815d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); 6825d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki if (ret) 6835d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki return ret; 6845d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki 6855d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki ret = v4l2_ctrl_handler_setup(&info->handle); 6865d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki info->ctrl_sync = !ret; 687bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 688bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 689bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 690bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 691bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 692bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * m5mols_start_monitor - Start the monitor mode 693bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 694bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * Before applying the controls setup the resolution and frame rate 695bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * in PARAMETER mode, and then switch over to MONITOR mode. 696bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 697bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_start_monitor(struct m5mols_info *info) 698bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 699bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev *sd = &info->sd; 700bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 701bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 7023c5da0baaada8e8c7176a3e310dfdb4362f74d80Sylwester Nawrocki ret = m5mols_set_mode(info, REG_PARAMETER); 703bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 704bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution); 705bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 706bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30); 707bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 7083c5da0baaada8e8c7176a3e310dfdb4362f74d80Sylwester Nawrocki ret = m5mols_set_mode(info, REG_MONITOR); 709bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 7105d4294b8ddf92092ffad61fe552adeeabb4242bdSylwester Nawrocki ret = m5mols_restore_controls(info); 711bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 712bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 713bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 714bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 715bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_s_stream(struct v4l2_subdev *sd, int enable) 716bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 717bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info = to_m5mols(sd); 7185565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki u32 code; 7195565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki int ret; 720bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 7215565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki mutex_lock(&info->lock); 7225565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki code = info->ffmt[info->res_type].code; 723bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 7245565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki if (enable) { 725fbe78ddde1f217044ed854eff92e4d22112871cbSylwester Nawrocki if (is_code(code, M5MOLS_RESTYPE_MONITOR)) 726bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_start_monitor(info); 7276ba4d05e84eeb450011f7f3514ec8556d3b46743Andrzej Hajda else if (is_code(code, M5MOLS_RESTYPE_CAPTURE)) 728bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_start_capture(info); 7295565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki else 7305565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki ret = -EINVAL; 7315565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki } else { 7325565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki ret = m5mols_set_mode(info, REG_PARAMETER); 733bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 734bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 7355565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki mutex_unlock(&info->lock); 7365565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki return ret; 737bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 738bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 739bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic const struct v4l2_subdev_video_ops m5mols_video_ops = { 740bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .s_stream = m5mols_s_stream, 741bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 742bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 743bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_sensor_power(struct m5mols_info *info, bool enable) 744bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 745bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev *sd = &info->sd; 746bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct i2c_client *client = v4l2_get_subdevdata(sd); 747bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim const struct m5mols_platform_data *pdata = info->pdata; 748bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 749bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 7500f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim if (info->power == enable) 7510f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim return 0; 752bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 7530f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim if (enable) { 754bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (info->set_power) { 755bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = info->set_power(&client->dev, 1); 756bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) 757bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 758bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 759bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 760bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); 761bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) { 762bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->set_power(&client->dev, 0); 763bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 764bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 765bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 766bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity); 7670f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim info->power = 1; 768bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 769bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 770bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 771bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 772bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); 773bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) 774bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 775bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 776bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (info->set_power) 777bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->set_power(&client->dev, 0); 778bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 779bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim gpio_set_value(pdata->gpio_reset, pdata->reset_polarity); 7800f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim 7810f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim info->isp_ready = 0; 7820f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim info->power = 0; 783bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 784bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 785bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 786bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 787bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/* m5mols_update_fw - optional firmware update routine */ 788bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimint __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd, 789bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int (*set_power)(struct m5mols_info *, bool)) 790bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 791bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 792bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 793bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 794bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 7950f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim * m5mols_fw_start - M-5MOLS internal ARM controller initialization 796bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 7970f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim * Execute the M-5MOLS internal ARM controller initialization sequence. 7980f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim * This function should be called after the supply voltage has been 7990f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim * applied and before any requests to the device are made. 800bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 8010f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kimstatic int m5mols_fw_start(struct v4l2_subdev *sd) 802bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 8030f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim struct m5mols_info *info = to_m5mols(sd); 804bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 805bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 8060f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim atomic_set(&info->irq_done, 0); 8070f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim /* Wait until I2C slave is initialized in Flash Writer mode */ 8080f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim ret = m5mols_busy_wait(sd, FLASH_CAM_START, REG_IN_FLASH_MODE, 8090f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim M5MOLS_I2C_RDY_WAIT_FL | 0xff, -1); 8100f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim if (!ret) 8110f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); 8120f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim if (!ret) 8130f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim ret = m5mols_wait_interrupt(sd, REG_INT_MODE, 2000); 814bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret < 0) 815bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 816bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 8170f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim info->isp_ready = 1; 818bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 819bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_get_version(sd); 820bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 821bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_update_fw(sd, m5mols_sensor_power); 822bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) 823bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 824bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 825bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n"); 826bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 827bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI); 828bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 82992e93a1fd065c8dfa592b01d3cb681e83bfc98ebHeungJun Kim ret = m5mols_enable_interrupt(sd, 83092e93a1fd065c8dfa592b01d3cb681e83bfc98ebHeungJun Kim REG_INT_AF | REG_INT_CAPTURE); 831bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 832bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 833bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 834bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 8355565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki/* Execute the lens soft-landing algorithm */ 8365565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrockistatic int m5mols_auto_focus_stop(struct m5mols_info *info) 8375565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki{ 8385565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki int ret; 8395565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki 8405565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP); 8415565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki if (!ret) 8425565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki ret = m5mols_write(&info->sd, AF_MODE, REG_AF_POWEROFF); 8435565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki if (!ret) 8445565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki ret = m5mols_busy_wait(&info->sd, SYSTEM_STATUS, REG_AF_IDLE, 8455565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki 0xff, -1); 8465565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki return ret; 8475565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki} 8485565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki 849bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim/** 850bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * m5mols_s_power - Main sensor power control function 851bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * 852bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * To prevent breaking the lens when the sensor is powered off the Soft-Landing 853bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * algorithm is called where available. The Soft-Landing algorithm availability 854bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim * dependends on the firmware provider. 855bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim */ 856bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_s_power(struct v4l2_subdev *sd, int on) 857bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 858bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info = to_m5mols(sd); 859bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 860bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 8615565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki mutex_lock(&info->lock); 8625565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki 863bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (on) { 864bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = m5mols_sensor_power(info, true); 865bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!ret) 8660f2ee1dd4907e1daae3c4bf00467417aba04c53eHeungJun Kim ret = m5mols_fw_start(sd); 8675565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki } else { 8685565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { 8695565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki ret = m5mols_set_mode(info, REG_MONITOR); 8705565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki if (!ret) 8715565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki ret = m5mols_auto_focus_stop(info); 8725565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki if (ret < 0) 8735565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki v4l2_warn(sd, "Soft landing lens failed\n"); 8745565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki } 8755565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki ret = m5mols_sensor_power(info, false); 876bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 8775565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki info->ctrl_sync = 0; 878bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 879bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 8805565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki mutex_unlock(&info->lock); 881bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 882bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 883bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 884bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic int m5mols_log_status(struct v4l2_subdev *sd) 885bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 886bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info = to_m5mols(sd); 887bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 888bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_ctrl_handler_log_status(&info->handle, sd->name); 889bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 890bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 891bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 892bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 893bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic const struct v4l2_subdev_core_ops m5mols_core_ops = { 894bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .s_power = m5mols_s_power, 895bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .log_status = m5mols_log_status, 896bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 897bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 898aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki/* 899aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki * V4L2 subdev internal operations 900aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki */ 901aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrockistatic int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 902aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki{ 903aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); 904aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki 905aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki *format = m5mols_default_ffmt[0]; 906aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki return 0; 907aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki} 908aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki 909aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrockistatic const struct v4l2_subdev_internal_ops m5mols_subdev_internal_ops = { 910aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki .open = m5mols_open, 911aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki}; 912aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki 913bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic const struct v4l2_subdev_ops m5mols_ops = { 914bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .core = &m5mols_core_ops, 915bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .pad = &m5mols_pad_ops, 916bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .video = &m5mols_video_ops, 917bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 918bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 919bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic irqreturn_t m5mols_irq_handler(int irq, void *data) 920bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 921ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim struct m5mols_info *info = to_m5mols(data); 922bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 923ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim atomic_set(&info->irq_done, 1); 924ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim wake_up_interruptible(&info->irq_waitq); 925bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 926bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return IRQ_HANDLED; 927bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 928bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 9294c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartmanstatic int m5mols_probe(struct i2c_client *client, 9304c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartman const struct i2c_device_id *id) 931bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 932bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim const struct m5mols_platform_data *pdata = client->dev.platform_data; 93395323361e5313733a54771c5059f5b352adbf32cLaurent Pinchart unsigned long gpio_flags; 934bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct m5mols_info *info; 935bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev *sd; 936bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim int ret; 937bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 938bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (pdata == NULL) { 939bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim dev_err(&client->dev, "No platform data\n"); 940bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -EINVAL; 941bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 942bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 943bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!gpio_is_valid(pdata->gpio_reset)) { 944bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim dev_err(&client->dev, "No valid RESET GPIO specified\n"); 945bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -EINVAL; 946bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 947bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 9485b3bdfce675040b65a8b97f8209d78a31935c48fSylwester Nawrocki if (!client->irq) { 949bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim dev_err(&client->dev, "Interrupt not assigned\n"); 950bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -EINVAL; 951bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 952bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 953c02b211df6fc54e51ee554c27a6736a11255a764Laurent Pinchart info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); 954bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (!info) 955bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return -ENOMEM; 956bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 957bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->pdata = pdata; 958bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->set_power = pdata->set_power; 959bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 96095323361e5313733a54771c5059f5b352adbf32cLaurent Pinchart gpio_flags = pdata->reset_polarity 96195323361e5313733a54771c5059f5b352adbf32cLaurent Pinchart ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; 962b015ba29ca09b0e3750b4de365d3baf9c5b11450Laurent Pinchart ret = devm_gpio_request_one(&client->dev, pdata->gpio_reset, gpio_flags, 963b015ba29ca09b0e3750b4de365d3baf9c5b11450Laurent Pinchart "M5MOLS_NRST"); 964bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) { 965bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim dev_err(&client->dev, "Failed to request gpio: %d\n", ret); 966c02b211df6fc54e51ee554c27a6736a11255a764Laurent Pinchart return ret; 967bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 968bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 96907e0e5b287421fcc4f4dbe2c0c8bfbc02e23a51eLaurent Pinchart ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), 97007e0e5b287421fcc4f4dbe2c0c8bfbc02e23a51eLaurent Pinchart supplies); 971bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) { 972bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim dev_err(&client->dev, "Failed to get regulators: %d\n", ret); 973b015ba29ca09b0e3750b4de365d3baf9c5b11450Laurent Pinchart return ret; 974bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 975bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 976bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim sd = &info->sd; 977bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_i2c_subdev_init(sd, client, &m5mols_ops); 978c5024a70bb60b678f08586ed786340ec162d250fSylwester Nawrocki strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); 97987eaec5dff4e20228fb6ac72dc849fd12f4e86beSylwester Nawrocki sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 980bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 981aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki sd->internal_ops = &m5mols_subdev_internal_ops; 982bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->pad.flags = MEDIA_PAD_FL_SOURCE; 983bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim ret = media_entity_init(&sd->entity, 1, &info->pad, 0); 984bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret < 0) 98507e0e5b287421fcc4f4dbe2c0c8bfbc02e23a51eLaurent Pinchart return ret; 986bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; 987bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 988bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim init_waitqueue_head(&info->irq_waitq); 9895565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki mutex_init(&info->lock); 9905565a2ad47cdd8e697a28137bd8379455667bc1cSylwester Nawrocki 991736db646b676e20542a98a95968ef806b25b794bLaurent Pinchart ret = devm_request_irq(&client->dev, client->irq, m5mols_irq_handler, 992736db646b676e20542a98a95968ef806b25b794bLaurent Pinchart IRQF_TRIGGER_RISING, MODULE_NAME, sd); 993bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim if (ret) { 994bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim dev_err(&client->dev, "Interrupt request failed: %d\n", ret); 995736db646b676e20542a98a95968ef806b25b794bLaurent Pinchart goto error; 996bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim } 997bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim info->res_type = M5MOLS_RESTYPE_MONITOR; 998f428948b98e3b9476057ee483e7e763a5ac61a69Sylwester Nawrocki info->ffmt[0] = m5mols_default_ffmt[0]; 999f428948b98e3b9476057ee483e7e763a5ac61a69Sylwester Nawrocki info->ffmt[1] = m5mols_default_ffmt[1]; 1000ce808a478ae5b79e52ea170b35c459829296330fHeungJun Kim 1001aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki ret = m5mols_sensor_power(info, true); 1002aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki if (ret) 1003736db646b676e20542a98a95968ef806b25b794bLaurent Pinchart goto error; 1004aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki 1005aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki ret = m5mols_fw_start(sd); 1006aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki if (!ret) 10073c5da0baaada8e8c7176a3e310dfdb4362f74d80Sylwester Nawrocki ret = m5mols_init_controls(sd); 1008aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki 1009b25b895805dd415f218cfd4892d17aeb2db425f7Julia Lawall ret = m5mols_sensor_power(info, false); 1010aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki if (!ret) 1011aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki return 0; 1012736db646b676e20542a98a95968ef806b25b794bLaurent Pincharterror: 1013bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim media_entity_cleanup(&sd->entity); 1014bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return ret; 1015bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 1016bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 10174c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartmanstatic int m5mols_remove(struct i2c_client *client) 1018bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim{ 1019bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim struct v4l2_subdev *sd = i2c_get_clientdata(client); 1020bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 1021bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim v4l2_device_unregister_subdev(sd); 1022aa1f4601ed35820a9bd720cc5b1e3fe3c4ff7c5fSylwester Nawrocki v4l2_ctrl_handler_free(sd->ctrl_handler); 1023bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim media_entity_cleanup(&sd->entity); 1024c02b211df6fc54e51ee554c27a6736a11255a764Laurent Pinchart 1025bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim return 0; 1026bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim} 1027bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 1028bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic const struct i2c_device_id m5mols_id[] = { 1029bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { MODULE_NAME, 0 }, 1030bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim { }, 1031bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 1032bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, KimMODULE_DEVICE_TABLE(i2c, m5mols_id); 1033bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 1034bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kimstatic struct i2c_driver m5mols_i2c_driver = { 1035bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .driver = { 1036bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .name = MODULE_NAME, 1037bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim }, 1038bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .probe = m5mols_probe, 10394c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartman .remove = m5mols_remove, 1040bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim .id_table = m5mols_id, 1041bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim}; 1042bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 1043c6e8d86fffd8edf1bfccbd441b1812ee919fe3d5Axel Linmodule_i2c_driver(m5mols_i2c_driver); 1044bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, Kim 1045bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, KimMODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>"); 1046bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, KimMODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>"); 1047bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, KimMODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver"); 1048bc125106f8afe15ffb0aae70d9b72bebec46e519HeungJun, KimMODULE_LICENSE("GPL"); 1049