2019-05-27 08:55:21 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2012-03-03 17:19:52 -03:00
/*
2020-02-11 19:05:57 +01:00
* drivers / media / i2c / ccs / ccs - quirk . c
2012-03-03 17:19:52 -03:00
*
2020-02-11 19:05:57 +01:00
* Generic driver for MIPI CCS / SMIA / SMIA + + compliant camera sensors
2012-03-03 17:19:52 -03:00
*
2020-02-11 19:05:57 +01:00
* Copyright ( C ) 2020 Intel Corporation
2012-03-03 17:19:52 -03:00
* Copyright ( C ) 2011 - - 2012 Nokia Corporation
2012-10-28 06:44:17 -03:00
* Contact : Sakari Ailus < sakari . ailus @ iki . fi >
2012-03-03 17:19:52 -03:00
*/
# include <linux/delay.h>
2020-02-11 14:19:13 +01:00
# include "ccs.h"
2020-02-10 10:09:03 +01:00
# include "ccs-limits.h"
2020-02-11 14:19:13 +01:00
static int ccs_write_addr_8s ( struct ccs_sensor * sensor ,
const struct ccs_reg_8 * regs , int len )
2012-03-03 17:19:52 -03:00
{
struct i2c_client * client = v4l2_get_subdevdata ( & sensor - > src - > sd ) ;
int rval ;
for ( ; len > 0 ; len - - , regs + + ) {
2020-02-11 12:16:14 +01:00
rval = ccs_write_addr ( sensor , regs - > reg , regs - > val ) ;
2012-03-03 17:19:52 -03:00
if ( rval < 0 ) {
dev_err ( & client - > dev ,
" error %d writing reg 0x%4.4x, val 0x%2.2x " ,
rval , regs - > reg , regs - > val ) ;
return rval ;
}
}
return 0 ;
}
2020-02-11 14:19:13 +01:00
static int jt8ew9_limits ( struct ccs_sensor * sensor )
2012-03-03 17:19:52 -03:00
{
if ( sensor - > minfo . revision_number_major < 0x03 )
sensor - > frame_skip = 1 ;
/* Below 24 gain doesn't have effect at all, */
/* but ~59 is needed for full dynamic range */
2020-02-10 10:09:03 +01:00
ccs_replace_limit ( sensor , CCS_L_ANALOG_GAIN_CODE_MIN , 0 , 59 ) ;
ccs_replace_limit ( sensor , CCS_L_ANALOG_GAIN_CODE_MAX , 0 , 6000 ) ;
2012-03-03 17:19:52 -03:00
return 0 ;
}
2020-02-11 14:19:13 +01:00
static int jt8ew9_post_poweron ( struct ccs_sensor * sensor )
2012-03-03 17:19:52 -03:00
{
2020-02-11 14:19:13 +01:00
static const struct ccs_reg_8 regs [ ] = {
2012-03-03 17:19:52 -03:00
{ 0x30a3 , 0xd8 } , /* Output port control : LVDS ports only */
{ 0x30ae , 0x00 } , /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
{ 0x30af , 0xd0 } , /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
{ 0x322d , 0x04 } , /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */
{ 0x3255 , 0x0f } , /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
{ 0x3256 , 0x15 } , /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
{ 0x3258 , 0x70 } , /* Analog Gain Control Toshiba Recommendation Setting */
{ 0x3259 , 0x70 } , /* Analog Gain Control Toshiba Recommendation Setting */
{ 0x325f , 0x7c } , /* Analog Gain Control Toshiba Recommendation Setting */
{ 0x3302 , 0x06 } , /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
{ 0x3304 , 0x00 } , /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
{ 0x3307 , 0x22 } , /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
{ 0x3308 , 0x8d } , /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
{ 0x331e , 0x0f } , /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
{ 0x3320 , 0x30 } , /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
{ 0x3321 , 0x11 } , /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
{ 0x3322 , 0x98 } , /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
{ 0x3323 , 0x64 } , /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
{ 0x3325 , 0x83 } , /* Read Out Timing Control Toshiba Recommendation Setting */
{ 0x3330 , 0x18 } , /* Read Out Timing Control Toshiba Recommendation Setting */
{ 0x333c , 0x01 } , /* Read Out Timing Control Toshiba Recommendation Setting */
{ 0x3345 , 0x2f } , /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
{ 0x33de , 0x38 } , /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
/* Taken from v03. No idea what the rest are. */
{ 0x32e0 , 0x05 } ,
{ 0x32e1 , 0x05 } ,
{ 0x32e2 , 0x04 } ,
{ 0x32e5 , 0x04 } ,
{ 0x32e6 , 0x04 } ,
} ;
2020-02-11 12:16:14 +01:00
return ccs_write_addr_8s ( sensor , regs , ARRAY_SIZE ( regs ) ) ;
2012-03-03 17:19:52 -03:00
}
2020-02-11 14:19:13 +01:00
const struct ccs_quirk smiapp_jt8ew9_quirk = {
2012-03-03 17:19:52 -03:00
. limits = jt8ew9_limits ,
. post_poweron = jt8ew9_post_poweron ,
} ;
2020-02-11 14:19:13 +01:00
static int imx125es_post_poweron ( struct ccs_sensor * sensor )
2012-03-03 17:19:52 -03:00
{
/* Taken from v02. No idea what the other two are. */
2020-02-11 14:19:13 +01:00
static const struct ccs_reg_8 regs [ ] = {
2012-03-03 17:19:52 -03:00
/*
* 0x3302 : clk during frame blanking :
* 0x00 - HS mode , 0x01 - LP11
*/
{ 0x3302 , 0x01 } ,
{ 0x302d , 0x00 } ,
{ 0x3b08 , 0x8c } ,
} ;
2020-02-11 12:16:14 +01:00
return ccs_write_addr_8s ( sensor , regs , ARRAY_SIZE ( regs ) ) ;
2012-03-03 17:19:52 -03:00
}
2020-02-11 14:19:13 +01:00
const struct ccs_quirk smiapp_imx125es_quirk = {
2012-03-03 17:19:52 -03:00
. post_poweron = imx125es_post_poweron ,
} ;
2020-02-11 14:19:13 +01:00
static int jt8ev1_limits ( struct ccs_sensor * sensor )
2012-03-03 17:19:52 -03:00
{
2020-02-10 10:09:03 +01:00
ccs_replace_limit ( sensor , CCS_L_X_ADDR_MAX , 0 , 4271 ) ;
ccs_replace_limit ( sensor , CCS_L_MIN_LINE_BLANKING_PCK_BIN , 0 , 184 ) ;
2012-03-03 17:19:52 -03:00
return 0 ;
}
2020-02-11 14:19:13 +01:00
static int jt8ev1_post_poweron ( struct ccs_sensor * sensor )
2012-03-03 17:19:52 -03:00
{
struct i2c_client * client = v4l2_get_subdevdata ( & sensor - > src - > sd ) ;
int rval ;
2020-02-11 14:19:13 +01:00
static const struct ccs_reg_8 regs [ ] = {
2012-03-03 17:19:52 -03:00
{ 0x3031 , 0xcd } , /* For digital binning (EQ_MONI) */
{ 0x30a3 , 0xd0 } , /* FLASH STROBE enable */
{ 0x3237 , 0x00 } , /* For control of pulse timing for ADC */
{ 0x3238 , 0x43 } ,
{ 0x3301 , 0x06 } , /* For analog bias for sensor */
{ 0x3302 , 0x06 } ,
{ 0x3304 , 0x00 } ,
{ 0x3305 , 0x88 } ,
{ 0x332a , 0x14 } ,
{ 0x332c , 0x6b } ,
{ 0x3336 , 0x01 } ,
{ 0x333f , 0x1f } ,
{ 0x3355 , 0x00 } ,
{ 0x3356 , 0x20 } ,
{ 0x33bf , 0x20 } , /* Adjust the FBC speed */
{ 0x33c9 , 0x20 } ,
{ 0x33ce , 0x30 } , /* Adjust the parameter for logic function */
{ 0x33cf , 0xec } , /* For Black sun */
{ 0x3328 , 0x80 } , /* Ugh. No idea what's this. */
} ;
2020-02-11 14:19:13 +01:00
static const struct ccs_reg_8 regs_96 [ ] = {
2012-03-03 17:19:52 -03:00
{ 0x30ae , 0x00 } , /* For control of ADC clock */
{ 0x30af , 0xd0 } ,
{ 0x30b0 , 0x01 } ,
} ;
2020-02-11 12:16:14 +01:00
rval = ccs_write_addr_8s ( sensor , regs , ARRAY_SIZE ( regs ) ) ;
2012-03-03 17:19:52 -03:00
if ( rval < 0 )
return rval ;
2020-02-11 22:41:39 +01:00
switch ( sensor - > hwcfg . ext_clk ) {
2012-03-03 17:19:52 -03:00
case 9600000 :
2020-02-11 12:16:14 +01:00
return ccs_write_addr_8s ( sensor , regs_96 ,
2012-03-03 17:19:52 -03:00
ARRAY_SIZE ( regs_96 ) ) ;
default :
dev_warn ( & client - > dev , " no MSRs for %d Hz ext_clk \n " ,
2020-02-11 22:41:39 +01:00
sensor - > hwcfg . ext_clk ) ;
2012-03-03 17:19:52 -03:00
return 0 ;
}
}
2020-02-11 14:19:13 +01:00
static int jt8ev1_pre_streamon ( struct ccs_sensor * sensor )
2012-03-03 17:19:52 -03:00
{
2020-02-11 12:16:14 +01:00
return ccs_write_addr ( sensor , 0x3328 , 0x00 ) ;
2012-03-03 17:19:52 -03:00
}
2020-02-11 14:19:13 +01:00
static int jt8ev1_post_streamoff ( struct ccs_sensor * sensor )
2012-03-03 17:19:52 -03:00
{
int rval ;
/* Workaround: allows fast standby to work properly */
2020-02-11 12:16:14 +01:00
rval = ccs_write_addr ( sensor , 0x3205 , 0x04 ) ;
2012-03-03 17:19:52 -03:00
if ( rval < 0 )
return rval ;
/* Wait for 1 ms + one line => 2 ms is likely enough */
2019-05-08 11:11:53 -04:00
usleep_range ( 2000 , 2050 ) ;
2012-03-03 17:19:52 -03:00
/* Restore it */
2020-02-11 12:16:14 +01:00
rval = ccs_write_addr ( sensor , 0x3205 , 0x00 ) ;
2012-03-03 17:19:52 -03:00
if ( rval < 0 )
return rval ;
2020-02-11 12:16:14 +01:00
return ccs_write_addr ( sensor , 0x3328 , 0x80 ) ;
2012-03-03 17:19:52 -03:00
}
2020-02-11 14:19:13 +01:00
static int jt8ev1_init ( struct ccs_sensor * sensor )
2014-04-08 18:18:10 -03:00
{
2014-10-03 11:38:32 -03:00
sensor - > pll . flags | = SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE ;
return 0 ;
2014-04-08 18:18:10 -03:00
}
2020-02-11 14:19:13 +01:00
const struct ccs_quirk smiapp_jt8ev1_quirk = {
2012-03-03 17:19:52 -03:00
. limits = jt8ev1_limits ,
. post_poweron = jt8ev1_post_poweron ,
. pre_streamon = jt8ev1_pre_streamon ,
. post_streamoff = jt8ev1_post_streamoff ,
2014-10-03 11:38:32 -03:00
. init = jt8ev1_init ,
2012-03-03 17:19:52 -03:00
} ;
2020-02-11 14:19:13 +01:00
static int tcm8500md_limits ( struct ccs_sensor * sensor )
2012-03-03 17:19:52 -03:00
{
2020-02-10 10:09:03 +01:00
ccs_replace_limit ( sensor , CCS_L_MIN_PLL_IP_CLK_FREQ_MHZ , 0 , 2700000 ) ;
2012-03-03 17:19:52 -03:00
return 0 ;
}
2020-02-11 14:19:13 +01:00
const struct ccs_quirk smiapp_tcm8500md_quirk = {
2012-03-03 17:19:52 -03:00
. limits = tcm8500md_limits ,
} ;