^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Driver for Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * with embedded SoC ISP.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2011, Samsung Electronics Co., Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Sylwester Nawrocki <s.nawrocki@samsung.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Based on a driver authored by Dongsoo Nathaniel Kim.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 2009, Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/media.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/regulator/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <media/media-entity.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <media/v4l2-ctrls.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <media/v4l2-device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <media/v4l2-subdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <media/v4l2-mediabus.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <media/i2c/s5k6aa.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static int debug;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) module_param(debug, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define DRIVER_NAME "S5K6AA"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /* The token to indicate array termination */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define S5K6AA_TERM 0xffff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define S5K6AA_OUT_WIDTH_DEF 640
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define S5K6AA_OUT_HEIGHT_DEF 480
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define S5K6AA_WIN_WIDTH_MAX 1280
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define S5K6AA_WIN_HEIGHT_MAX 1024
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define S5K6AA_WIN_WIDTH_MIN 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define S5K6AA_WIN_HEIGHT_MIN 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * H/W register Interface (0xD0000000 - 0xD0000FFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define AHB_MSB_ADDR_PTR 0xfcfc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define GEN_REG_OFFSH 0xd000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define REG_CMDWR_ADDRH 0x0028
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define REG_CMDWR_ADDRL 0x002a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define REG_CMDRD_ADDRH 0x002c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define REG_CMDRD_ADDRL 0x002e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define REG_CMDBUF0_ADDR 0x0f12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define REG_CMDBUF1_ADDR 0x0f10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * Host S/W Register interface (0x70000000 - 0x70002000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * The value of the two most significant address bytes is 0x7000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * (HOST_SWIF_OFFS_H). The register addresses below specify 2 LSBs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define HOST_SWIF_OFFSH 0x7000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* Initialization parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* Master clock frequency in KHz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define REG_I_INCLK_FREQ_L 0x01b8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define REG_I_INCLK_FREQ_H 0x01ba
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define MIN_MCLK_FREQ_KHZ 6000U
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define MAX_MCLK_FREQ_KHZ 27000U
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define REG_I_USE_NPVI_CLOCKS 0x01c6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define REG_I_USE_NMIPI_CLOCKS 0x01c8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define REG_I_OPCLK_4KHZ(n) ((n) * 6 + 0x01cc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define REG_I_MIN_OUTRATE_4KHZ(n) ((n) * 6 + 0x01ce)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define REG_I_MAX_OUTRATE_4KHZ(n) ((n) * 6 + 0x01d0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define SYS_PLL_OUT_FREQ (48000000 / 4000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define PCLK_FREQ_MIN (24000000 / 4000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define PCLK_FREQ_MAX (48000000 / 4000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define REG_I_INIT_PARAMS_UPDATED 0x01e0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define REG_I_ERROR_INFO 0x01e2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* General purpose parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define REG_USER_BRIGHTNESS 0x01e4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define REG_USER_CONTRAST 0x01e6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define REG_USER_SATURATION 0x01e8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define REG_USER_SHARPBLUR 0x01ea
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define REG_G_SPEC_EFFECTS 0x01ee
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define REG_G_ENABLE_PREV 0x01f0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define REG_G_ENABLE_PREV_CHG 0x01f2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define REG_G_NEW_CFG_SYNC 0x01f8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define REG_G_PREVZOOM_IN_WIDTH 0x020a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) #define REG_G_PREVZOOM_IN_HEIGHT 0x020c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define REG_G_PREVZOOM_IN_XOFFS 0x020e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define REG_G_PREVZOOM_IN_YOFFS 0x0210
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define REG_G_INPUTS_CHANGE_REQ 0x021a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define REG_G_ACTIVE_PREV_CFG 0x021c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #define REG_G_PREV_CFG_CHG 0x021e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #define REG_G_PREV_OPEN_AFTER_CH 0x0220
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #define REG_G_PREV_CFG_ERROR 0x0222
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* Preview control section. n = 0...4. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define PREG(n, x) ((n) * 0x26 + x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #define REG_P_OUT_WIDTH(n) PREG(n, 0x0242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define REG_P_OUT_HEIGHT(n) PREG(n, 0x0244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #define REG_P_FMT(n) PREG(n, 0x0246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #define REG_P_MAX_OUT_RATE(n) PREG(n, 0x0248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) #define REG_P_MIN_OUT_RATE(n) PREG(n, 0x024a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #define REG_P_PVI_MASK(n) PREG(n, 0x024c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define REG_P_CLK_INDEX(n) PREG(n, 0x024e)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) #define REG_P_FR_RATE_TYPE(n) PREG(n, 0x0250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) #define FR_RATE_DYNAMIC 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define FR_RATE_FIXED 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) #define FR_RATE_FIXED_ACCURATE 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) #define REG_P_FR_RATE_Q_TYPE(n) PREG(n, 0x0252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #define FR_RATE_Q_BEST_FRRATE 1 /* Binning enabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #define FR_RATE_Q_BEST_QUALITY 2 /* Binning disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) /* Frame period in 0.1 ms units */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define REG_P_MAX_FR_TIME(n) PREG(n, 0x0254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #define REG_P_MIN_FR_TIME(n) PREG(n, 0x0256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* Conversion to REG_P_[MAX/MIN]_FR_TIME value; __t: time in us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #define US_TO_FR_TIME(__t) ((__t) / 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #define S5K6AA_MIN_FR_TIME 33300 /* us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define S5K6AA_MAX_FR_TIME 650000 /* us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #define S5K6AA_MAX_HIGHRES_FR_TIME 666 /* x100 us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* The below 5 registers are for "device correction" values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) #define REG_P_COLORTEMP(n) PREG(n, 0x025e)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) #define REG_P_PREV_MIRROR(n) PREG(n, 0x0262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /* Extended image property controls */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* Exposure time in 10 us units */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) #define REG_SF_USR_EXPOSURE_L 0x03c6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) #define REG_SF_USR_EXPOSURE_H 0x03c8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) #define REG_SF_USR_EXPOSURE_CHG 0x03ca
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #define REG_SF_USR_TOT_GAIN 0x03cc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #define REG_SF_USR_TOT_GAIN_CHG 0x03ce
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #define REG_SF_RGAIN 0x03d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #define REG_SF_RGAIN_CHG 0x03d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #define REG_SF_GGAIN 0x03d4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) #define REG_SF_GGAIN_CHG 0x03d6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #define REG_SF_BGAIN 0x03d8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #define REG_SF_BGAIN_CHG 0x03da
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #define REG_SF_FLICKER_QUANT 0x03dc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) #define REG_SF_FLICKER_QUANT_CHG 0x03de
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /* Output interface (parallel/MIPI) setup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) #define REG_OIF_EN_MIPI_LANES 0x03fa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) #define REG_OIF_EN_PACKETS 0x03fc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #define REG_OIF_CFG_CHG 0x03fe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /* Auto-algorithms enable mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #define REG_DBG_AUTOALG_EN 0x0400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) #define AALG_ALL_EN_MASK (1 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) #define AALG_AE_EN_MASK (1 << 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) #define AALG_DIVLEI_EN_MASK (1 << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) #define AALG_WB_EN_MASK (1 << 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) #define AALG_FLICKER_EN_MASK (1 << 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) #define AALG_FIT_EN_MASK (1 << 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) #define AALG_WRHW_EN_MASK (1 << 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /* Firmware revision information */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) #define REG_FW_APIVER 0x012e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) #define S5K6AAFX_FW_APIVER 0x0001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) #define REG_FW_REVISION 0x0130
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /* For now we use only one user configuration register set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #define S5K6AA_MAX_PRESETS 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static const char * const s5k6aa_supply_names[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) "vdd_core", /* Digital core supply 1.5V (1.4V to 1.6V) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) "vdda", /* Analog power supply 2.8V (2.6V to 3.0V) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) "vdd_reg", /* Regulator input power 1.8V (1.7V to 1.9V)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) or 2.8V (2.6V to 3.0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) "vddio", /* I/O supply 1.8V (1.65V to 1.95V)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) or 2.8V (2.5V to 3.1V) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) #define S5K6AA_NUM_SUPPLIES ARRAY_SIZE(s5k6aa_supply_names)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) enum s5k6aa_gpio_id {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) STBY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) RSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) GPIO_NUM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct s5k6aa_regval {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) u16 addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) u16 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct s5k6aa_pixfmt {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) u32 code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) u32 colorspace;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) /* REG_P_FMT(x) register value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) u16 reg_p_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) struct s5k6aa_preset {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) /* output pixel format and resolution */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct v4l2_mbus_framefmt mbus_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) u8 clk_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) u8 index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct s5k6aa_ctrls {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct v4l2_ctrl_handler handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) /* Auto / manual white balance cluster */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) struct v4l2_ctrl *awb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) struct v4l2_ctrl *gain_red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) struct v4l2_ctrl *gain_blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) struct v4l2_ctrl *gain_green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) /* Mirror cluster */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) struct v4l2_ctrl *hflip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) struct v4l2_ctrl *vflip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* Auto exposure / manual exposure and gain cluster */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) struct v4l2_ctrl *auto_exp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct v4l2_ctrl *exposure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct v4l2_ctrl *gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) struct s5k6aa_interval {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) u16 reg_fr_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) struct v4l2_fract interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) /* Maximum rectangle for the interval */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) struct v4l2_frmsize_discrete size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) struct s5k6aa {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) struct v4l2_subdev sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) struct media_pad pad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) enum v4l2_mbus_type bus_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) u8 mipi_lanes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) int (*s_power)(int enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) struct regulator_bulk_data supplies[S5K6AA_NUM_SUPPLIES];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) struct s5k6aa_gpio gpio[GPIO_NUM];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) /* external master clock frequency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) unsigned long mclk_frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) /* ISP internal master clock frequency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) u16 clk_fop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /* output pixel clock frequency range */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) u16 pclk_fmin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) u16 pclk_fmax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) unsigned int inv_hflip:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) unsigned int inv_vflip:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) /* protects the struct members below */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) struct mutex lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /* sensor matrix scan window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) struct v4l2_rect ccd_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) struct s5k6aa_ctrls ctrls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) struct s5k6aa_preset presets[S5K6AA_MAX_PRESETS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) struct s5k6aa_preset *preset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) const struct s5k6aa_interval *fiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) unsigned int streaming:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) unsigned int apply_cfg:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) unsigned int apply_crop:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) unsigned int power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static struct s5k6aa_regval s5k6aa_analog_config[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) /* Analog settings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) { 0x112a, 0x0000 }, { 0x1132, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) { 0x113e, 0x0000 }, { 0x115c, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) { 0x1164, 0x0000 }, { 0x1174, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) { 0x1178, 0x0000 }, { 0x077a, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) { 0x077c, 0x0000 }, { 0x077e, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) { 0x0780, 0x0000 }, { 0x0782, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) { 0x0784, 0x0000 }, { 0x0786, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) { 0x0788, 0x0000 }, { 0x07a2, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) { 0x07a4, 0x0000 }, { 0x07a6, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) { 0x07a8, 0x0000 }, { 0x07b6, 0x0000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) { 0x07b8, 0x0002 }, { 0x07ba, 0x0004 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) { 0x07bc, 0x0004 }, { 0x07be, 0x0005 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) { 0x07c0, 0x0005 }, { S5K6AA_TERM, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) /* TODO: Add RGB888 and Bayer format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) static const struct s5k6aa_pixfmt s5k6aa_formats[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) /* range 16-240 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_REC709, 6 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) static const struct s5k6aa_interval s5k6aa_intervals[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) { 1000, {10000, 1000000}, {1280, 1024} }, /* 10 fps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) { 666, {15000, 1000000}, {1280, 1024} }, /* 15 fps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) { 500, {20000, 1000000}, {1280, 720} }, /* 20 fps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) { 400, {25000, 1000000}, {640, 480} }, /* 25 fps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) { 333, {33300, 1000000}, {640, 480} }, /* 30 fps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) #define S5K6AA_INTERVAL_DEF_INDEX 1 /* 15 fps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return &container_of(ctrl->handler, struct s5k6aa, ctrls.handler)->sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) static inline struct s5k6aa *to_s5k6aa(struct v4l2_subdev *sd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return container_of(sd, struct s5k6aa, sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) /* Set initial values for all preview presets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) static void s5k6aa_presets_data_init(struct s5k6aa *s5k6aa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) struct s5k6aa_preset *preset = &s5k6aa->presets[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) for (i = 0; i < S5K6AA_MAX_PRESETS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) preset->mbus_fmt.width = S5K6AA_OUT_WIDTH_DEF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) preset->mbus_fmt.height = S5K6AA_OUT_HEIGHT_DEF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) preset->mbus_fmt.code = s5k6aa_formats[0].code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) preset->index = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) preset->clk_id = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) preset++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) s5k6aa->fiv = &s5k6aa_intervals[S5K6AA_INTERVAL_DEF_INDEX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) s5k6aa->preset = &s5k6aa->presets[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) u8 wbuf[2] = {addr >> 8, addr & 0xFF};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) struct i2c_msg msg[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) u8 rbuf[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) msg[0].addr = client->addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) msg[0].flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) msg[0].len = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) msg[0].buf = wbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) msg[1].addr = client->addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) msg[1].flags = I2C_M_RD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) msg[1].len = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) msg[1].buf = rbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) ret = i2c_transfer(client->adapter, msg, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) *val = be16_to_cpu(*((__be16 *)rbuf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) return ret == 2 ? 0 : ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) static int s5k6aa_i2c_write(struct i2c_client *client, u16 addr, u16 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) u8 buf[4] = {addr >> 8, addr & 0xFF, val >> 8, val & 0xFF};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) int ret = i2c_master_send(client, buf, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) v4l2_dbg(3, debug, client, "i2c_write: 0x%04X : 0x%04x\n", addr, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return ret == 4 ? 0 : ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) /* The command register write, assumes Command_Wr_addH = 0x7000. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) static int s5k6aa_write(struct i2c_client *c, u16 addr, u16 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) int ret = s5k6aa_i2c_write(c, REG_CMDWR_ADDRL, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return s5k6aa_i2c_write(c, REG_CMDBUF0_ADDR, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) /* The command register read, assumes Command_Rd_addH = 0x7000. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) static int s5k6aa_read(struct i2c_client *client, u16 addr, u16 *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) int ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRL, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) return s5k6aa_i2c_read(client, REG_CMDBUF0_ADDR, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) static int s5k6aa_write_array(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) const struct s5k6aa_regval *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) struct i2c_client *client = v4l2_get_subdevdata(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) u16 addr_incr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) while (msg->addr != S5K6AA_TERM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (addr_incr != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) ret = s5k6aa_i2c_write(client, REG_CMDWR_ADDRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) msg->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) ret = s5k6aa_i2c_write(client, REG_CMDBUF0_ADDR, msg->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) /* Assume that msg->addr is always less than 0xfffc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) addr_incr = (msg + 1)->addr - msg->addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) msg++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) /* Configure the AHB high address bytes for GTG registers access */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) static int s5k6aa_set_ahb_address(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) int ret = s5k6aa_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRH, HOST_SWIF_OFFSH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) return s5k6aa_i2c_write(client, REG_CMDWR_ADDRH, HOST_SWIF_OFFSH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) * s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) * @s5k6aa: pointer to &struct s5k6aa describing the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) * Configure the internal ISP PLL for the required output frequency.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) * Locking: called with s5k6aa.lock mutex held.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) static int s5k6aa_configure_pixel_clocks(struct s5k6aa *s5k6aa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) unsigned long fmclk = s5k6aa->mclk_frequency / 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) u16 status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (WARN(fmclk < MIN_MCLK_FREQ_KHZ || fmclk > MAX_MCLK_FREQ_KHZ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) "Invalid clock frequency: %ld\n", fmclk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) s5k6aa->pclk_fmin = PCLK_FREQ_MIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) s5k6aa->pclk_fmax = PCLK_FREQ_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) s5k6aa->clk_fop = SYS_PLL_OUT_FREQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) /* External input clock frequency in kHz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) ret = s5k6aa_write(c, REG_I_INCLK_FREQ_H, fmclk >> 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) ret = s5k6aa_write(c, REG_I_INCLK_FREQ_L, fmclk & 0xFFFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) ret = s5k6aa_write(c, REG_I_USE_NPVI_CLOCKS, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) /* Internal PLL frequency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) ret = s5k6aa_write(c, REG_I_OPCLK_4KHZ(0), s5k6aa->clk_fop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) ret = s5k6aa_write(c, REG_I_MIN_OUTRATE_4KHZ(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) s5k6aa->pclk_fmin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) ret = s5k6aa_write(c, REG_I_MAX_OUTRATE_4KHZ(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) s5k6aa->pclk_fmax);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) ret = s5k6aa_write(c, REG_I_INIT_PARAMS_UPDATED, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) ret = s5k6aa_read(c, REG_I_ERROR_INFO, &status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) return ret ? ret : (status ? -EINVAL : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) /* Set horizontal and vertical image flipping */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) static int s5k6aa_set_mirror(struct s5k6aa *s5k6aa, int horiz_flip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) int index = s5k6aa->preset->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) unsigned int vflip = s5k6aa->ctrls.vflip->val ^ s5k6aa->inv_vflip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) unsigned int flip = (horiz_flip ^ s5k6aa->inv_hflip) | (vflip << 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) return s5k6aa_write(client, REG_P_PREV_MIRROR(index), flip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) /* Configure auto/manual white balance and R/G/B gains */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) static int s5k6aa_set_awb(struct s5k6aa *s5k6aa, int awb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) u16 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (!ret && !awb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) ret = s5k6aa_write(c, REG_SF_RGAIN, ctrls->gain_red->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) ret = s5k6aa_write(c, REG_SF_RGAIN_CHG, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) ret = s5k6aa_write(c, REG_SF_GGAIN, ctrls->gain_green->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) ret = s5k6aa_write(c, REG_SF_GGAIN_CHG, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) ret = s5k6aa_write(c, REG_SF_BGAIN, ctrls->gain_blue->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) ret = s5k6aa_write(c, REG_SF_BGAIN_CHG, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) reg = awb ? reg | AALG_WB_EN_MASK : reg & ~AALG_WB_EN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) ret = s5k6aa_write(c, REG_DBG_AUTOALG_EN, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) /* Program FW with exposure time, 'exposure' in us units */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) static int s5k6aa_set_user_exposure(struct i2c_client *client, int exposure)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) unsigned int time = exposure / 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) int ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_L, time & 0xffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_H, time >> 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return s5k6aa_write(client, REG_SF_USR_EXPOSURE_CHG, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) static int s5k6aa_set_user_gain(struct i2c_client *client, int gain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) int ret = s5k6aa_write(client, REG_SF_USR_TOT_GAIN, gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) return s5k6aa_write(client, REG_SF_USR_TOT_GAIN_CHG, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) /* Set auto/manual exposure and total gain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) static int s5k6aa_set_auto_exposure(struct s5k6aa *s5k6aa, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) unsigned int exp_time = s5k6aa->ctrls.exposure->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) u16 auto_alg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &auto_alg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) v4l2_dbg(1, debug, c, "man_exp: %d, auto_exp: %d, a_alg: 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) exp_time, value, auto_alg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (value == V4L2_EXPOSURE_AUTO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) auto_alg |= AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) ret = s5k6aa_set_user_exposure(c, exp_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) ret = s5k6aa_set_user_gain(c, s5k6aa->ctrls.gain->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) auto_alg &= ~(AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) return s5k6aa_write(c, REG_DBG_AUTOALG_EN, auto_alg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) static int s5k6aa_set_anti_flicker(struct s5k6aa *s5k6aa, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) u16 auto_alg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) ret = s5k6aa_read(client, REG_DBG_AUTOALG_EN, &auto_alg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) if (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) auto_alg |= AALG_FLICKER_EN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) auto_alg &= ~AALG_FLICKER_EN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) /* The V4L2_CID_LINE_FREQUENCY control values match
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) * the register values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT_CHG, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) return s5k6aa_write(client, REG_DBG_AUTOALG_EN, auto_alg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) static int s5k6aa_set_colorfx(struct s5k6aa *s5k6aa, int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) static const struct v4l2_control colorfx[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) { V4L2_COLORFX_NONE, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) { V4L2_COLORFX_BW, 1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) { V4L2_COLORFX_NEGATIVE, 2 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) { V4L2_COLORFX_SEPIA, 3 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) { V4L2_COLORFX_SKY_BLUE, 4 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) { V4L2_COLORFX_SKETCH, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) for (i = 0; i < ARRAY_SIZE(colorfx); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) if (colorfx[i].id == val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) return s5k6aa_write(client, REG_G_SPEC_EFFECTS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) colorfx[i].value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) static int s5k6aa_preview_config_status(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) u16 error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) int ret = s5k6aa_read(client, REG_G_PREV_CFG_ERROR, &error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) v4l2_dbg(1, debug, client, "error: 0x%x (%d)\n", error, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) return ret ? ret : (error ? -EINVAL : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) static int s5k6aa_get_pixfmt_index(struct s5k6aa *s5k6aa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) struct v4l2_mbus_framefmt *mf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) for (i = 0; i < ARRAY_SIZE(s5k6aa_formats); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (mf->colorspace == s5k6aa_formats[i].colorspace &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) mf->code == s5k6aa_formats[i].code)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) static int s5k6aa_set_output_framefmt(struct s5k6aa *s5k6aa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) struct s5k6aa_preset *preset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) int fmt_index = s5k6aa_get_pixfmt_index(s5k6aa, &preset->mbus_fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) ret = s5k6aa_write(client, REG_P_OUT_WIDTH(preset->index),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) preset->mbus_fmt.width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) ret = s5k6aa_write(client, REG_P_OUT_HEIGHT(preset->index),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) preset->mbus_fmt.height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) ret = s5k6aa_write(client, REG_P_FMT(preset->index),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) s5k6aa_formats[fmt_index].reg_p_fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) struct v4l2_rect *r = &s5k6aa->ccd_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) ret = s5k6aa_write(c, REG_G_INPUTS_CHANGE_REQ, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) s5k6aa->apply_crop = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) * s5k6aa_configure_video_bus - configure the video output interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) * @s5k6aa: pointer to &struct s5k6aa describing the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) * @bus_type: video bus type: parallel or MIPI-CSI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) * @nlanes: number of MIPI lanes to be used (MIPI-CSI only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) * Note: Only parallel bus operation has been tested.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) enum v4l2_mbus_type bus_type, int nlanes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) u16 cfg = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) * TODO: The sensor is supposed to support BT.601 and BT.656
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) * but there is nothing indicating how to switch between both
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) * in the datasheet. For now default BT.601 interface is assumed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) if (bus_type == V4L2_MBUS_CSI2_DPHY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) cfg = nlanes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) else if (bus_type != V4L2_MBUS_PARALLEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) ret = s5k6aa_write(client, REG_OIF_EN_MIPI_LANES, cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) return s5k6aa_write(client, REG_OIF_CFG_CHG, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) /* This function should be called when switching to new user configuration set*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) int cid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) unsigned long end = jiffies + msecs_to_jiffies(timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) u16 reg = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) ret = s5k6aa_write(client, REG_G_ACTIVE_PREV_CFG, cid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) ret = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) ret = s5k6aa_write(client, REG_G_NEW_CFG_SYNC, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) if (timeout == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) while (ret >= 0 && time_is_after_jiffies(end)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) ret = s5k6aa_read(client, REG_G_NEW_CFG_SYNC, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) if (!reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) usleep_range(1000, 5000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) return ret ? ret : -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) * s5k6aa_set_prev_config - write user preview register set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) * @s5k6aa: pointer to &struct s5k6aa describing the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) * @preset: s5kaa preset to be applied
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) * Configure output resolution and color format, pixel clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) * frequency range, device frame rate type and frame period range.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) struct s5k6aa_preset *preset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) int idx = preset->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) u16 frame_rate_q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) if (s5k6aa->fiv->reg_fr_time >= S5K6AA_MAX_HIGHRES_FR_TIME)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) frame_rate_q = FR_RATE_Q_BEST_FRRATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) frame_rate_q = FR_RATE_Q_BEST_QUALITY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) ret = s5k6aa_set_output_framefmt(s5k6aa, preset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) ret = s5k6aa_write(client, REG_P_MAX_OUT_RATE(idx),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) s5k6aa->pclk_fmax);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) ret = s5k6aa_write(client, REG_P_MIN_OUT_RATE(idx),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) s5k6aa->pclk_fmin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) ret = s5k6aa_write(client, REG_P_CLK_INDEX(idx),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) preset->clk_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) ret = s5k6aa_write(client, REG_P_FR_RATE_TYPE(idx),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) FR_RATE_DYNAMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) ret = s5k6aa_write(client, REG_P_FR_RATE_Q_TYPE(idx),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) frame_rate_q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) ret = s5k6aa_write(client, REG_P_MAX_FR_TIME(idx),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) s5k6aa->fiv->reg_fr_time + 33);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) ret = s5k6aa_write(client, REG_P_MIN_FR_TIME(idx),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) s5k6aa->fiv->reg_fr_time - 33);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) ret = s5k6aa_new_config_sync(client, 250, idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) ret = s5k6aa_preview_config_status(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) s5k6aa->apply_cfg = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) v4l2_dbg(1, debug, client, "Frame interval: %d +/- 3.3ms. (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) s5k6aa->fiv->reg_fr_time, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) * s5k6aa_initialize_isp - basic ISP MCU initialization
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) * @sd: pointer to V4L2 sub-device descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) * Configure AHB addresses for registers read/write; configure PLLs for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) * required output pixel clock. The ISP power supply needs to be already
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) * enabled, with an optional H/W reset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) * Locking: called with s5k6aa.lock mutex held.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) static int s5k6aa_initialize_isp(struct v4l2_subdev *sd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) struct i2c_client *client = v4l2_get_subdevdata(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) struct s5k6aa *s5k6aa = to_s5k6aa(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) s5k6aa->apply_crop = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) s5k6aa->apply_cfg = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) msleep(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) ret = s5k6aa_set_ahb_address(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) ret = s5k6aa_configure_video_bus(s5k6aa, s5k6aa->bus_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) s5k6aa->mipi_lanes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) ret = s5k6aa_write_array(sd, s5k6aa_analog_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) msleep(20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) return s5k6aa_configure_pixel_clocks(s5k6aa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) static int s5k6aa_gpio_set_value(struct s5k6aa *priv, int id, u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) if (!gpio_is_valid(priv->gpio[id].gpio))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) gpio_set_value(priv->gpio[id].gpio, !!val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) static int s5k6aa_gpio_assert(struct s5k6aa *priv, int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) return s5k6aa_gpio_set_value(priv, id, priv->gpio[id].level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) static int s5k6aa_gpio_deassert(struct s5k6aa *priv, int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) return s5k6aa_gpio_set_value(priv, id, !priv->gpio[id].level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) static int __s5k6aa_power_on(struct s5k6aa *s5k6aa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) ret = regulator_bulk_enable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) if (s5k6aa_gpio_deassert(s5k6aa, STBY))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) usleep_range(150, 200);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) if (s5k6aa->s_power)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) ret = s5k6aa->s_power(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) usleep_range(4000, 5000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) if (s5k6aa_gpio_deassert(s5k6aa, RSET))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) msleep(20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) static int __s5k6aa_power_off(struct s5k6aa *s5k6aa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) if (s5k6aa_gpio_assert(s5k6aa, RSET))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) usleep_range(100, 150);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) if (s5k6aa->s_power) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) ret = s5k6aa->s_power(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) if (s5k6aa_gpio_assert(s5k6aa, STBY))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) usleep_range(50, 100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) s5k6aa->streaming = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) return regulator_bulk_disable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) * V4L2 subdev core and video operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) static int s5k6aa_set_power(struct v4l2_subdev *sd, int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) struct s5k6aa *s5k6aa = to_s5k6aa(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) mutex_lock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) if (s5k6aa->power == !on) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) if (on) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) ret = __s5k6aa_power_on(s5k6aa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) ret = s5k6aa_initialize_isp(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) ret = __s5k6aa_power_off(s5k6aa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) s5k6aa->power += on ? 1 : -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) mutex_unlock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) if (!on || ret || s5k6aa->power != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) return v4l2_ctrl_handler_setup(sd->ctrl_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) static int __s5k6aa_stream(struct s5k6aa *s5k6aa, int enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) ret = s5k6aa_write(client, REG_G_ENABLE_PREV, enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) ret = s5k6aa_write(client, REG_G_ENABLE_PREV_CHG, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) s5k6aa->streaming = enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) static int s5k6aa_s_stream(struct v4l2_subdev *sd, int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) struct s5k6aa *s5k6aa = to_s5k6aa(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) mutex_lock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) if (s5k6aa->streaming == !on) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) if (!ret && s5k6aa->apply_cfg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) ret = s5k6aa_set_prev_config(s5k6aa, s5k6aa->preset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) if (s5k6aa->apply_crop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) ret = s5k6aa_set_input_params(s5k6aa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) ret = __s5k6aa_stream(s5k6aa, !!on);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) mutex_unlock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) static int s5k6aa_g_frame_interval(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) struct v4l2_subdev_frame_interval *fi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) struct s5k6aa *s5k6aa = to_s5k6aa(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) mutex_lock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) fi->interval = s5k6aa->fiv->interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) mutex_unlock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) static int __s5k6aa_set_frame_interval(struct s5k6aa *s5k6aa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) struct v4l2_subdev_frame_interval *fi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) struct v4l2_mbus_framefmt *mbus_fmt = &s5k6aa->preset->mbus_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) const struct s5k6aa_interval *fiv = &s5k6aa_intervals[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) unsigned int err, min_err = UINT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) unsigned int i, fr_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) if (fi->interval.denominator == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) fr_time = fi->interval.numerator * 10000 / fi->interval.denominator;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) for (i = 0; i < ARRAY_SIZE(s5k6aa_intervals); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) const struct s5k6aa_interval *iv = &s5k6aa_intervals[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) if (mbus_fmt->width > iv->size.width ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) mbus_fmt->height > iv->size.height)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) err = abs(iv->reg_fr_time - fr_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) if (err < min_err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) fiv = iv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) min_err = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) s5k6aa->fiv = fiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) v4l2_dbg(1, debug, &s5k6aa->sd, "Changed frame interval to %d us\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) fiv->reg_fr_time * 100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) struct v4l2_subdev_frame_interval *fi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) struct s5k6aa *s5k6aa = to_s5k6aa(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) fi->interval.numerator, fi->interval.denominator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) mutex_lock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) ret = __s5k6aa_set_frame_interval(s5k6aa, fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) s5k6aa->apply_cfg = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) mutex_unlock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) * V4L2 subdev pad level and video operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) struct v4l2_subdev_frame_interval_enum *fie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) struct s5k6aa *s5k6aa = to_s5k6aa(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) const struct s5k6aa_interval *fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) if (fie->index >= ARRAY_SIZE(s5k6aa_intervals))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) S5K6AA_WIN_WIDTH_MAX, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) &fie->height, S5K6AA_WIN_HEIGHT_MIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) S5K6AA_WIN_HEIGHT_MAX, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) mutex_lock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) fi = &s5k6aa_intervals[fie->index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) if (fie->width > fi->size.width || fie->height > fi->size.height)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) fie->interval = fi->interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) mutex_unlock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) struct v4l2_subdev_mbus_code_enum *code)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) if (code->index >= ARRAY_SIZE(s5k6aa_formats))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) code->code = s5k6aa_formats[code->index].code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) struct v4l2_subdev_frame_size_enum *fse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) int i = ARRAY_SIZE(s5k6aa_formats);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) if (fse->index > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) while (--i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) if (fse->code == s5k6aa_formats[i].code)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) fse->code = s5k6aa_formats[i].code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) fse->min_width = S5K6AA_WIN_WIDTH_MIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) fse->max_width = S5K6AA_WIN_WIDTH_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) fse->max_height = S5K6AA_WIN_HEIGHT_MIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) fse->min_height = S5K6AA_WIN_HEIGHT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) static struct v4l2_rect *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) __s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) enum v4l2_subdev_format_whence which)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) return &s5k6aa->ccd_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) WARN_ON(which != V4L2_SUBDEV_FORMAT_TRY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) return v4l2_subdev_get_try_crop(&s5k6aa->sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) static void s5k6aa_try_format(struct s5k6aa *s5k6aa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) struct v4l2_mbus_framefmt *mf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) unsigned int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) v4l_bound_align_image(&mf->width, S5K6AA_WIN_WIDTH_MIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) S5K6AA_WIN_WIDTH_MAX, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) &mf->height, S5K6AA_WIN_HEIGHT_MIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) S5K6AA_WIN_HEIGHT_MAX, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) if (mf->colorspace != V4L2_COLORSPACE_JPEG &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) mf->colorspace != V4L2_COLORSPACE_REC709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) mf->colorspace = V4L2_COLORSPACE_JPEG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) index = s5k6aa_get_pixfmt_index(s5k6aa, mf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) mf->colorspace = s5k6aa_formats[index].colorspace;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) mf->code = s5k6aa_formats[index].code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) mf->field = V4L2_FIELD_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) struct v4l2_subdev_format *fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) struct s5k6aa *s5k6aa = to_s5k6aa(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) struct v4l2_mbus_framefmt *mf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) memset(fmt->reserved, 0, sizeof(fmt->reserved));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) mf = v4l2_subdev_get_try_format(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) fmt->format = *mf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) mutex_lock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) fmt->format = s5k6aa->preset->mbus_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) mutex_unlock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) struct v4l2_subdev_format *fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) struct s5k6aa *s5k6aa = to_s5k6aa(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) struct s5k6aa_preset *preset = s5k6aa->preset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) struct v4l2_mbus_framefmt *mf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) struct v4l2_rect *crop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) mutex_lock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) s5k6aa_try_format(s5k6aa, &fmt->format);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) crop = v4l2_subdev_get_try_crop(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) if (s5k6aa->streaming) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) mf = &preset->mbus_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) crop = &s5k6aa->ccd_rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) s5k6aa->apply_cfg = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) if (ret == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) struct v4l2_subdev_frame_interval fiv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) .interval = {0, 1}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) *mf = fmt->format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) * Make sure the crop window is valid, i.e. its size is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) * greater than the output window, as the ISP supports
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) * only down-scaling.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) crop->width = clamp_t(unsigned int, crop->width, mf->width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) S5K6AA_WIN_WIDTH_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) crop->height = clamp_t(unsigned int, crop->height, mf->height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) S5K6AA_WIN_HEIGHT_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) crop->left = clamp_t(unsigned int, crop->left, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) S5K6AA_WIN_WIDTH_MAX - crop->width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) crop->top = clamp_t(unsigned int, crop->top, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) S5K6AA_WIN_HEIGHT_MAX - crop->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) /* Reset to minimum possible frame interval */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) ret = __s5k6aa_set_frame_interval(s5k6aa, &fiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) mutex_unlock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) static int s5k6aa_get_selection(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) struct v4l2_subdev_selection *sel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) struct s5k6aa *s5k6aa = to_s5k6aa(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) struct v4l2_rect *rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) if (sel->target != V4L2_SEL_TGT_CROP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) memset(sel->reserved, 0, sizeof(sel->reserved));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) mutex_lock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) rect = __s5k6aa_get_crop_rect(s5k6aa, cfg, sel->which);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) sel->r = *rect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) mutex_unlock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) rect->left, rect->top, rect->width, rect->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) static int s5k6aa_set_selection(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) struct v4l2_subdev_selection *sel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) struct s5k6aa *s5k6aa = to_s5k6aa(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) struct v4l2_mbus_framefmt *mf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) unsigned int max_x, max_y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) struct v4l2_rect *crop_r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) if (sel->target != V4L2_SEL_TGT_CROP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) mutex_lock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) crop_r = __s5k6aa_get_crop_rect(s5k6aa, cfg, sel->which);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) mf = &s5k6aa->preset->mbus_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) s5k6aa->apply_crop = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) mf = v4l2_subdev_get_try_format(sd, cfg, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) v4l_bound_align_image(&sel->r.width, mf->width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) S5K6AA_WIN_WIDTH_MAX, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) &sel->r.height, mf->height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) S5K6AA_WIN_HEIGHT_MAX, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) max_x = (S5K6AA_WIN_WIDTH_MAX - sel->r.width) & ~1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) max_y = (S5K6AA_WIN_HEIGHT_MAX - sel->r.height) & ~1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) sel->r.left = clamp_t(unsigned int, sel->r.left, 0, max_x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) sel->r.top = clamp_t(unsigned int, sel->r.top, 0, max_y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) *crop_r = sel->r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) mutex_unlock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) v4l2_dbg(1, debug, sd, "Set crop rectangle: (%d,%d)/%dx%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) crop_r->left, crop_r->top, crop_r->width, crop_r->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) .enum_mbus_code = s5k6aa_enum_mbus_code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) .enum_frame_size = s5k6aa_enum_frame_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) .enum_frame_interval = s5k6aa_enum_frame_interval,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) .get_fmt = s5k6aa_get_fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) .set_fmt = s5k6aa_set_fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) .get_selection = s5k6aa_get_selection,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) .set_selection = s5k6aa_set_selection,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) static const struct v4l2_subdev_video_ops s5k6aa_video_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) .g_frame_interval = s5k6aa_g_frame_interval,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) .s_frame_interval = s5k6aa_s_frame_interval,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) .s_stream = s5k6aa_s_stream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) * V4L2 subdev controls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) static int s5k6aa_s_ctrl(struct v4l2_ctrl *ctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) struct i2c_client *client = v4l2_get_subdevdata(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) struct s5k6aa *s5k6aa = to_s5k6aa(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) int idx, err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) mutex_lock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) * If the device is not powered up by the host driver do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) * not apply any controls to H/W at this time. Instead
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) * the controls will be restored right after power-up.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) if (s5k6aa->power == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) idx = s5k6aa->preset->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) switch (ctrl->id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) case V4L2_CID_AUTO_WHITE_BALANCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) err = s5k6aa_set_awb(s5k6aa, ctrl->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) case V4L2_CID_BRIGHTNESS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) err = s5k6aa_write(client, REG_USER_BRIGHTNESS, ctrl->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) case V4L2_CID_COLORFX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) err = s5k6aa_set_colorfx(s5k6aa, ctrl->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) case V4L2_CID_CONTRAST:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) err = s5k6aa_write(client, REG_USER_CONTRAST, ctrl->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) case V4L2_CID_EXPOSURE_AUTO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) err = s5k6aa_set_auto_exposure(s5k6aa, ctrl->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) case V4L2_CID_HFLIP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) err = s5k6aa_set_mirror(s5k6aa, ctrl->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) case V4L2_CID_POWER_LINE_FREQUENCY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) err = s5k6aa_set_anti_flicker(s5k6aa, ctrl->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) case V4L2_CID_SATURATION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) err = s5k6aa_write(client, REG_USER_SATURATION, ctrl->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) case V4L2_CID_SHARPNESS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) err = s5k6aa_write(client, REG_USER_SHARPBLUR, ctrl->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) err = s5k6aa_write(client, REG_P_COLORTEMP(idx), ctrl->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) mutex_unlock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) static const struct v4l2_ctrl_ops s5k6aa_ctrl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) .s_ctrl = s5k6aa_s_ctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) static int s5k6aa_log_status(struct v4l2_subdev *sd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) #define V4L2_CID_RED_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) #define V4L2_CID_GREEN_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1002)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) #define V4L2_CID_BLUE_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) static const struct v4l2_ctrl_config s5k6aa_ctrls[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) .ops = &s5k6aa_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) .id = V4L2_CID_RED_GAIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) .type = V4L2_CTRL_TYPE_INTEGER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) .name = "Gain, Red",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) .min = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) .max = 256,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) .def = 127,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) .step = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) .ops = &s5k6aa_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) .id = V4L2_CID_GREEN_GAIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) .type = V4L2_CTRL_TYPE_INTEGER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) .name = "Gain, Green",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) .min = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) .max = 256,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) .def = 127,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) .step = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) .ops = &s5k6aa_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) .id = V4L2_CID_BLUE_GAIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) .type = V4L2_CTRL_TYPE_INTEGER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) .name = "Gain, Blue",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) .min = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) .max = 256,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) .def = 127,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) .step = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) const struct v4l2_ctrl_ops *ops = &s5k6aa_ctrl_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) struct v4l2_ctrl_handler *hdl = &ctrls->handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) int ret = v4l2_ctrl_handler_init(hdl, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) /* Auto white balance cluster */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) 0, 1, 1, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) ctrls->gain_red = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[0], NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) ctrls->gain_green = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[1], NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) ctrls->gain_blue = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[2], NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) v4l2_ctrl_auto_cluster(4, &ctrls->awb, 0, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) v4l2_ctrl_cluster(2, &ctrls->hflip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) V4L2_CID_EXPOSURE_AUTO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) /* Exposure time: x 1 us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) 0, 6000000U, 1, 100000U);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) /* Total gain: 256 <=> 1x */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) 0, 256, 1, 256);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) 0, 256, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) if (hdl->error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) ret = hdl->error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) v4l2_ctrl_handler_free(hdl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) s5k6aa->sd.ctrl_handler = hdl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) * V4L2 subdev internal operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) format->colorspace = s5k6aa_formats[0].colorspace;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) format->code = s5k6aa_formats[0].code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) format->width = S5K6AA_OUT_WIDTH_DEF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) format->height = S5K6AA_OUT_HEIGHT_DEF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) format->field = V4L2_FIELD_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) crop->width = S5K6AA_WIN_WIDTH_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) crop->height = S5K6AA_WIN_HEIGHT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) crop->left = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) crop->top = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) static int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) u16 api_ver = 0, fw_rev = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) int ret = s5k6aa_set_ahb_address(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) ret = s5k6aa_read(client, REG_FW_APIVER, &api_ver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) ret = s5k6aa_read(client, REG_FW_REVISION, &fw_rev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) v4l2_err(&s5k6aa->sd, "FW revision check failed!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) v4l2_info(&s5k6aa->sd, "FW API ver.: 0x%X, FW rev.: 0x%X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) api_ver, fw_rev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) return api_ver == S5K6AAFX_FW_APIVER ? 0 : -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) static int s5k6aa_registered(struct v4l2_subdev *sd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) struct s5k6aa *s5k6aa = to_s5k6aa(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) mutex_lock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) ret = __s5k6aa_power_on(s5k6aa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) msleep(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) ret = s5k6aa_check_fw_revision(s5k6aa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) __s5k6aa_power_off(s5k6aa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) mutex_unlock(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) static const struct v4l2_subdev_internal_ops s5k6aa_subdev_internal_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) .registered = s5k6aa_registered,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) .open = s5k6aa_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) static const struct v4l2_subdev_core_ops s5k6aa_core_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) .s_power = s5k6aa_set_power,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) .log_status = s5k6aa_log_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) static const struct v4l2_subdev_ops s5k6aa_subdev_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) .core = &s5k6aa_core_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) .pad = &s5k6aa_pad_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) .video = &s5k6aa_video_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) * GPIO setup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) const struct s5k6aa_platform_data *pdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) const struct s5k6aa_gpio *gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) s5k6aa->gpio[STBY].gpio = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) s5k6aa->gpio[RSET].gpio = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) gpio = &pdata->gpio_stby;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) if (gpio_is_valid(gpio->gpio)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) | GPIOF_EXPORT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) ret = devm_gpio_request_one(&client->dev, gpio->gpio, flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) "S5K6AA_STBY");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) s5k6aa->gpio[STBY] = *gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) gpio = &pdata->gpio_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) if (gpio_is_valid(gpio->gpio)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) | GPIOF_EXPORT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) ret = devm_gpio_request_one(&client->dev, gpio->gpio, flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) "S5K6AA_RST");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) s5k6aa->gpio[RSET] = *gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) static int s5k6aa_probe(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) const struct i2c_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) const struct s5k6aa_platform_data *pdata = client->dev.platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) struct v4l2_subdev *sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) struct s5k6aa *s5k6aa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) if (pdata == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) dev_err(&client->dev, "Platform data not specified\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) if (pdata->mclk_frequency == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) dev_err(&client->dev, "MCLK frequency not specified\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) s5k6aa = devm_kzalloc(&client->dev, sizeof(*s5k6aa), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) if (!s5k6aa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) mutex_init(&s5k6aa->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) s5k6aa->mclk_frequency = pdata->mclk_frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) s5k6aa->bus_type = pdata->bus_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) s5k6aa->mipi_lanes = pdata->nlanes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) s5k6aa->s_power = pdata->set_power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) s5k6aa->inv_hflip = pdata->horiz_flip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) s5k6aa->inv_vflip = pdata->vert_flip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) sd = &s5k6aa->sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) /* Static name; NEVER use in new drivers! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) strscpy(sd->name, DRIVER_NAME, sizeof(sd->name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) sd->internal_ops = &s5k6aa_subdev_internal_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) ret = media_entity_pads_init(&sd->entity, 1, &s5k6aa->pad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) ret = s5k6aa_configure_gpios(s5k6aa, pdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) s5k6aa->supplies[i].supply = s5k6aa_supply_names[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) ret = devm_regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) s5k6aa->supplies);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) dev_err(&client->dev, "Failed to get regulators\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) ret = s5k6aa_initialize_ctrls(s5k6aa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) s5k6aa_presets_data_init(s5k6aa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) s5k6aa->ccd_rect.width = S5K6AA_WIN_WIDTH_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) s5k6aa->ccd_rect.height = S5K6AA_WIN_HEIGHT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) s5k6aa->ccd_rect.left = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) s5k6aa->ccd_rect.top = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) out_err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) media_entity_cleanup(&s5k6aa->sd.entity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) static int s5k6aa_remove(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) struct v4l2_subdev *sd = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) v4l2_device_unregister_subdev(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) v4l2_ctrl_handler_free(sd->ctrl_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) media_entity_cleanup(&sd->entity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) static const struct i2c_device_id s5k6aa_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) { DRIVER_NAME, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) MODULE_DEVICE_TABLE(i2c, s5k6aa_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) static struct i2c_driver s5k6aa_i2c_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) .name = DRIVER_NAME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) .probe = s5k6aa_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) .remove = s5k6aa_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) .id_table = s5k6aa_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) module_i2c_driver(s5k6aa_i2c_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) MODULE_LICENSE("GPL");