Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Driver for Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor
0004  * with embedded SoC ISP.
0005  *
0006  * Copyright (C) 2011, Samsung Electronics Co., Ltd.
0007  * Sylwester Nawrocki <s.nawrocki@samsung.com>
0008  *
0009  * Based on a driver authored by Dongsoo Nathaniel Kim.
0010  * Copyright (C) 2009, Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
0011  */
0012 
0013 #include <linux/clk.h>
0014 #include <linux/delay.h>
0015 #include <linux/gpio.h>
0016 #include <linux/i2c.h>
0017 #include <linux/media.h>
0018 #include <linux/module.h>
0019 #include <linux/regulator/consumer.h>
0020 #include <linux/slab.h>
0021 
0022 #include <media/media-entity.h>
0023 #include <media/v4l2-ctrls.h>
0024 #include <media/v4l2-device.h>
0025 #include <media/v4l2-subdev.h>
0026 #include <media/v4l2-mediabus.h>
0027 #include <media/i2c/s5k6aa.h>
0028 
0029 static int debug;
0030 module_param(debug, int, 0644);
0031 
0032 #define DRIVER_NAME         "S5K6AA"
0033 
0034 /* The token to indicate array termination */
0035 #define S5K6AA_TERM         0xffff
0036 #define S5K6AA_OUT_WIDTH_DEF        640
0037 #define S5K6AA_OUT_HEIGHT_DEF       480
0038 #define S5K6AA_WIN_WIDTH_MAX        1280
0039 #define S5K6AA_WIN_HEIGHT_MAX       1024
0040 #define S5K6AA_WIN_WIDTH_MIN        8
0041 #define S5K6AA_WIN_HEIGHT_MIN       8
0042 
0043 /*
0044  * H/W register Interface (0xD0000000 - 0xD0000FFF)
0045  */
0046 #define AHB_MSB_ADDR_PTR        0xfcfc
0047 #define GEN_REG_OFFSH           0xd000
0048 #define REG_CMDWR_ADDRH         0x0028
0049 #define REG_CMDWR_ADDRL         0x002a
0050 #define REG_CMDRD_ADDRH         0x002c
0051 #define REG_CMDRD_ADDRL         0x002e
0052 #define REG_CMDBUF0_ADDR        0x0f12
0053 #define REG_CMDBUF1_ADDR        0x0f10
0054 
0055 /*
0056  * Host S/W Register interface (0x70000000 - 0x70002000)
0057  * The value of the two most significant address bytes is 0x7000,
0058  * (HOST_SWIF_OFFS_H). The register addresses below specify 2 LSBs.
0059  */
0060 #define HOST_SWIF_OFFSH         0x7000
0061 
0062 /* Initialization parameters */
0063 /* Master clock frequency in KHz */
0064 #define REG_I_INCLK_FREQ_L      0x01b8
0065 #define REG_I_INCLK_FREQ_H      0x01ba
0066 #define  MIN_MCLK_FREQ_KHZ      6000U
0067 #define  MAX_MCLK_FREQ_KHZ      27000U
0068 #define REG_I_USE_NPVI_CLOCKS       0x01c6
0069 #define REG_I_USE_NMIPI_CLOCKS      0x01c8
0070 
0071 /* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */
0072 #define REG_I_OPCLK_4KHZ(n)     ((n) * 6 + 0x01cc)
0073 #define REG_I_MIN_OUTRATE_4KHZ(n)   ((n) * 6 + 0x01ce)
0074 #define REG_I_MAX_OUTRATE_4KHZ(n)   ((n) * 6 + 0x01d0)
0075 #define  SYS_PLL_OUT_FREQ       (48000000 / 4000)
0076 #define  PCLK_FREQ_MIN          (24000000 / 4000)
0077 #define  PCLK_FREQ_MAX          (48000000 / 4000)
0078 #define REG_I_INIT_PARAMS_UPDATED   0x01e0
0079 #define REG_I_ERROR_INFO        0x01e2
0080 
0081 /* General purpose parameters */
0082 #define REG_USER_BRIGHTNESS     0x01e4
0083 #define REG_USER_CONTRAST       0x01e6
0084 #define REG_USER_SATURATION     0x01e8
0085 #define REG_USER_SHARPBLUR      0x01ea
0086 
0087 #define REG_G_SPEC_EFFECTS      0x01ee
0088 #define REG_G_ENABLE_PREV       0x01f0
0089 #define REG_G_ENABLE_PREV_CHG       0x01f2
0090 #define REG_G_NEW_CFG_SYNC      0x01f8
0091 #define REG_G_PREVZOOM_IN_WIDTH     0x020a
0092 #define REG_G_PREVZOOM_IN_HEIGHT    0x020c
0093 #define REG_G_PREVZOOM_IN_XOFFS     0x020e
0094 #define REG_G_PREVZOOM_IN_YOFFS     0x0210
0095 #define REG_G_INPUTS_CHANGE_REQ     0x021a
0096 #define REG_G_ACTIVE_PREV_CFG       0x021c
0097 #define REG_G_PREV_CFG_CHG      0x021e
0098 #define REG_G_PREV_OPEN_AFTER_CH    0x0220
0099 #define REG_G_PREV_CFG_ERROR        0x0222
0100 
0101 /* Preview control section. n = 0...4. */
0102 #define PREG(n, x)          ((n) * 0x26 + x)
0103 #define REG_P_OUT_WIDTH(n)      PREG(n, 0x0242)
0104 #define REG_P_OUT_HEIGHT(n)     PREG(n, 0x0244)
0105 #define REG_P_FMT(n)            PREG(n, 0x0246)
0106 #define REG_P_MAX_OUT_RATE(n)       PREG(n, 0x0248)
0107 #define REG_P_MIN_OUT_RATE(n)       PREG(n, 0x024a)
0108 #define REG_P_PVI_MASK(n)       PREG(n, 0x024c)
0109 #define REG_P_CLK_INDEX(n)      PREG(n, 0x024e)
0110 #define REG_P_FR_RATE_TYPE(n)       PREG(n, 0x0250)
0111 #define  FR_RATE_DYNAMIC        0
0112 #define  FR_RATE_FIXED          1
0113 #define  FR_RATE_FIXED_ACCURATE     2
0114 #define REG_P_FR_RATE_Q_TYPE(n)     PREG(n, 0x0252)
0115 #define  FR_RATE_Q_BEST_FRRATE      1 /* Binning enabled */
0116 #define  FR_RATE_Q_BEST_QUALITY     2 /* Binning disabled */
0117 /* Frame period in 0.1 ms units */
0118 #define REG_P_MAX_FR_TIME(n)        PREG(n, 0x0254)
0119 #define REG_P_MIN_FR_TIME(n)        PREG(n, 0x0256)
0120 /* Conversion to REG_P_[MAX/MIN]_FR_TIME value; __t: time in us */
0121 #define  US_TO_FR_TIME(__t)     ((__t) / 100)
0122 #define  S5K6AA_MIN_FR_TIME     33300  /* us */
0123 #define  S5K6AA_MAX_FR_TIME     650000 /* us */
0124 #define  S5K6AA_MAX_HIGHRES_FR_TIME 666    /* x100 us */
0125 /* The below 5 registers are for "device correction" values */
0126 #define REG_P_COLORTEMP(n)      PREG(n, 0x025e)
0127 #define REG_P_PREV_MIRROR(n)        PREG(n, 0x0262)
0128 
0129 /* Extended image property controls */
0130 /* Exposure time in 10 us units */
0131 #define REG_SF_USR_EXPOSURE_L       0x03c6
0132 #define REG_SF_USR_EXPOSURE_H       0x03c8
0133 #define REG_SF_USR_EXPOSURE_CHG     0x03ca
0134 #define REG_SF_USR_TOT_GAIN     0x03cc
0135 #define REG_SF_USR_TOT_GAIN_CHG     0x03ce
0136 #define REG_SF_RGAIN            0x03d0
0137 #define REG_SF_RGAIN_CHG        0x03d2
0138 #define REG_SF_GGAIN            0x03d4
0139 #define REG_SF_GGAIN_CHG        0x03d6
0140 #define REG_SF_BGAIN            0x03d8
0141 #define REG_SF_BGAIN_CHG        0x03da
0142 #define REG_SF_FLICKER_QUANT        0x03dc
0143 #define REG_SF_FLICKER_QUANT_CHG    0x03de
0144 
0145 /* Output interface (parallel/MIPI) setup */
0146 #define REG_OIF_EN_MIPI_LANES       0x03fa
0147 #define REG_OIF_EN_PACKETS      0x03fc
0148 #define REG_OIF_CFG_CHG         0x03fe
0149 
0150 /* Auto-algorithms enable mask */
0151 #define REG_DBG_AUTOALG_EN      0x0400
0152 #define  AALG_ALL_EN_MASK       (1 << 0)
0153 #define  AALG_AE_EN_MASK        (1 << 1)
0154 #define  AALG_DIVLEI_EN_MASK        (1 << 2)
0155 #define  AALG_WB_EN_MASK        (1 << 3)
0156 #define  AALG_FLICKER_EN_MASK       (1 << 5)
0157 #define  AALG_FIT_EN_MASK       (1 << 6)
0158 #define  AALG_WRHW_EN_MASK      (1 << 7)
0159 
0160 /* Firmware revision information */
0161 #define REG_FW_APIVER           0x012e
0162 #define  S5K6AAFX_FW_APIVER     0x0001
0163 #define REG_FW_REVISION         0x0130
0164 
0165 /* For now we use only one user configuration register set */
0166 #define S5K6AA_MAX_PRESETS      1
0167 
0168 static const char * const s5k6aa_supply_names[] = {
0169     "vdd_core", /* Digital core supply 1.5V (1.4V to 1.6V) */
0170     "vdda",     /* Analog power supply 2.8V (2.6V to 3.0V) */
0171     "vdd_reg",  /* Regulator input power 1.8V (1.7V to 1.9V)
0172                or 2.8V (2.6V to 3.0) */
0173     "vddio",    /* I/O supply 1.8V (1.65V to 1.95V)
0174                or 2.8V (2.5V to 3.1V) */
0175 };
0176 #define S5K6AA_NUM_SUPPLIES ARRAY_SIZE(s5k6aa_supply_names)
0177 
0178 enum s5k6aa_gpio_id {
0179     STBY,
0180     RSET,
0181     GPIO_NUM,
0182 };
0183 
0184 struct s5k6aa_regval {
0185     u16 addr;
0186     u16 val;
0187 };
0188 
0189 struct s5k6aa_pixfmt {
0190     u32 code;
0191     u32 colorspace;
0192     /* REG_P_FMT(x) register value */
0193     u16 reg_p_fmt;
0194 };
0195 
0196 struct s5k6aa_preset {
0197     /* output pixel format and resolution */
0198     struct v4l2_mbus_framefmt mbus_fmt;
0199     u8 clk_id;
0200     u8 index;
0201 };
0202 
0203 struct s5k6aa_ctrls {
0204     struct v4l2_ctrl_handler handler;
0205     /* Auto / manual white balance cluster */
0206     struct v4l2_ctrl *awb;
0207     struct v4l2_ctrl *gain_red;
0208     struct v4l2_ctrl *gain_blue;
0209     struct v4l2_ctrl *gain_green;
0210     /* Mirror cluster */
0211     struct v4l2_ctrl *hflip;
0212     struct v4l2_ctrl *vflip;
0213     /* Auto exposure / manual exposure and gain cluster */
0214     struct v4l2_ctrl *auto_exp;
0215     struct v4l2_ctrl *exposure;
0216     struct v4l2_ctrl *gain;
0217 };
0218 
0219 struct s5k6aa_interval {
0220     u16 reg_fr_time;
0221     struct v4l2_fract interval;
0222     /* Maximum rectangle for the interval */
0223     struct v4l2_frmsize_discrete size;
0224 };
0225 
0226 struct s5k6aa {
0227     struct v4l2_subdev sd;
0228     struct media_pad pad;
0229 
0230     enum v4l2_mbus_type bus_type;
0231     u8 mipi_lanes;
0232 
0233     int (*s_power)(int enable);
0234     struct regulator_bulk_data supplies[S5K6AA_NUM_SUPPLIES];
0235     struct s5k6aa_gpio gpio[GPIO_NUM];
0236 
0237     /* external master clock frequency */
0238     unsigned long mclk_frequency;
0239     /* ISP internal master clock frequency */
0240     u16 clk_fop;
0241     /* output pixel clock frequency range */
0242     u16 pclk_fmin;
0243     u16 pclk_fmax;
0244 
0245     unsigned int inv_hflip:1;
0246     unsigned int inv_vflip:1;
0247 
0248     /* protects the struct members below */
0249     struct mutex lock;
0250 
0251     /* sensor matrix scan window */
0252     struct v4l2_rect ccd_rect;
0253 
0254     struct s5k6aa_ctrls ctrls;
0255     struct s5k6aa_preset presets[S5K6AA_MAX_PRESETS];
0256     struct s5k6aa_preset *preset;
0257     const struct s5k6aa_interval *fiv;
0258 
0259     unsigned int streaming:1;
0260     unsigned int apply_cfg:1;
0261     unsigned int apply_crop:1;
0262     unsigned int power;
0263 };
0264 
0265 static struct s5k6aa_regval s5k6aa_analog_config[] = {
0266     /* Analog settings */
0267     { 0x112a, 0x0000 }, { 0x1132, 0x0000 },
0268     { 0x113e, 0x0000 }, { 0x115c, 0x0000 },
0269     { 0x1164, 0x0000 }, { 0x1174, 0x0000 },
0270     { 0x1178, 0x0000 }, { 0x077a, 0x0000 },
0271     { 0x077c, 0x0000 }, { 0x077e, 0x0000 },
0272     { 0x0780, 0x0000 }, { 0x0782, 0x0000 },
0273     { 0x0784, 0x0000 }, { 0x0786, 0x0000 },
0274     { 0x0788, 0x0000 }, { 0x07a2, 0x0000 },
0275     { 0x07a4, 0x0000 }, { 0x07a6, 0x0000 },
0276     { 0x07a8, 0x0000 }, { 0x07b6, 0x0000 },
0277     { 0x07b8, 0x0002 }, { 0x07ba, 0x0004 },
0278     { 0x07bc, 0x0004 }, { 0x07be, 0x0005 },
0279     { 0x07c0, 0x0005 }, { S5K6AA_TERM, 0 },
0280 };
0281 
0282 /* TODO: Add RGB888 and Bayer format */
0283 static const struct s5k6aa_pixfmt s5k6aa_formats[] = {
0284     { MEDIA_BUS_FMT_YUYV8_2X8,  V4L2_COLORSPACE_JPEG,   5 },
0285     /* range 16-240 */
0286     { MEDIA_BUS_FMT_YUYV8_2X8,  V4L2_COLORSPACE_REC709, 6 },
0287     { MEDIA_BUS_FMT_RGB565_2X8_BE,  V4L2_COLORSPACE_JPEG,   0 },
0288 };
0289 
0290 static const struct s5k6aa_interval s5k6aa_intervals[] = {
0291     { 1000, {10000, 1000000}, {1280, 1024} }, /* 10 fps */
0292     { 666,  {15000, 1000000}, {1280, 1024} }, /* 15 fps */
0293     { 500,  {20000, 1000000}, {1280, 720} },  /* 20 fps */
0294     { 400,  {25000, 1000000}, {640, 480} },   /* 25 fps */
0295     { 333,  {33300, 1000000}, {640, 480} },   /* 30 fps */
0296 };
0297 
0298 #define S5K6AA_INTERVAL_DEF_INDEX 1 /* 15 fps */
0299 
0300 static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
0301 {
0302     return &container_of(ctrl->handler, struct s5k6aa, ctrls.handler)->sd;
0303 }
0304 
0305 static inline struct s5k6aa *to_s5k6aa(struct v4l2_subdev *sd)
0306 {
0307     return container_of(sd, struct s5k6aa, sd);
0308 }
0309 
0310 /* Set initial values for all preview presets */
0311 static void s5k6aa_presets_data_init(struct s5k6aa *s5k6aa)
0312 {
0313     struct s5k6aa_preset *preset = &s5k6aa->presets[0];
0314     int i;
0315 
0316     for (i = 0; i < S5K6AA_MAX_PRESETS; i++) {
0317         preset->mbus_fmt.width  = S5K6AA_OUT_WIDTH_DEF;
0318         preset->mbus_fmt.height = S5K6AA_OUT_HEIGHT_DEF;
0319         preset->mbus_fmt.code   = s5k6aa_formats[0].code;
0320         preset->index       = i;
0321         preset->clk_id      = 0;
0322         preset++;
0323     }
0324 
0325     s5k6aa->fiv = &s5k6aa_intervals[S5K6AA_INTERVAL_DEF_INDEX];
0326     s5k6aa->preset = &s5k6aa->presets[0];
0327 }
0328 
0329 static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val)
0330 {
0331     u8 wbuf[2] = {addr >> 8, addr & 0xFF};
0332     struct i2c_msg msg[2];
0333     u8 rbuf[2];
0334     int ret;
0335 
0336     msg[0].addr = client->addr;
0337     msg[0].flags = 0;
0338     msg[0].len = 2;
0339     msg[0].buf = wbuf;
0340 
0341     msg[1].addr = client->addr;
0342     msg[1].flags = I2C_M_RD;
0343     msg[1].len = 2;
0344     msg[1].buf = rbuf;
0345 
0346     ret = i2c_transfer(client->adapter, msg, 2);
0347     *val = be16_to_cpu(*((__be16 *)rbuf));
0348 
0349     v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
0350 
0351     return ret == 2 ? 0 : ret;
0352 }
0353 
0354 static int s5k6aa_i2c_write(struct i2c_client *client, u16 addr, u16 val)
0355 {
0356     u8 buf[4] = {addr >> 8, addr & 0xFF, val >> 8, val & 0xFF};
0357 
0358     int ret = i2c_master_send(client, buf, 4);
0359     v4l2_dbg(3, debug, client, "i2c_write: 0x%04X : 0x%04x\n", addr, val);
0360 
0361     return ret == 4 ? 0 : ret;
0362 }
0363 
0364 /* The command register write, assumes Command_Wr_addH = 0x7000. */
0365 static int s5k6aa_write(struct i2c_client *c, u16 addr, u16 val)
0366 {
0367     int ret = s5k6aa_i2c_write(c, REG_CMDWR_ADDRL, addr);
0368     if (ret)
0369         return ret;
0370     return s5k6aa_i2c_write(c, REG_CMDBUF0_ADDR, val);
0371 }
0372 
0373 /* The command register read, assumes Command_Rd_addH = 0x7000. */
0374 static int s5k6aa_read(struct i2c_client *client, u16 addr, u16 *val)
0375 {
0376     int ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRL, addr);
0377     if (ret)
0378         return ret;
0379     return s5k6aa_i2c_read(client, REG_CMDBUF0_ADDR, val);
0380 }
0381 
0382 static int s5k6aa_write_array(struct v4l2_subdev *sd,
0383                   const struct s5k6aa_regval *msg)
0384 {
0385     struct i2c_client *client = v4l2_get_subdevdata(sd);
0386     u16 addr_incr = 0;
0387     int ret = 0;
0388 
0389     while (msg->addr != S5K6AA_TERM) {
0390         if (addr_incr != 2)
0391             ret = s5k6aa_i2c_write(client, REG_CMDWR_ADDRL,
0392                            msg->addr);
0393         if (ret)
0394             break;
0395         ret = s5k6aa_i2c_write(client, REG_CMDBUF0_ADDR, msg->val);
0396         if (ret)
0397             break;
0398         /* Assume that msg->addr is always less than 0xfffc */
0399         addr_incr = (msg + 1)->addr - msg->addr;
0400         msg++;
0401     }
0402 
0403     return ret;
0404 }
0405 
0406 /* Configure the AHB high address bytes for GTG registers access */
0407 static int s5k6aa_set_ahb_address(struct i2c_client *client)
0408 {
0409     int ret = s5k6aa_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH);
0410     if (ret)
0411         return ret;
0412     ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRH, HOST_SWIF_OFFSH);
0413     if (ret)
0414         return ret;
0415     return s5k6aa_i2c_write(client, REG_CMDWR_ADDRH, HOST_SWIF_OFFSH);
0416 }
0417 
0418 /**
0419  * s5k6aa_configure_pixel_clocks - apply ISP main clock/PLL configuration
0420  * @s5k6aa: pointer to &struct s5k6aa describing the device
0421  *
0422  * Configure the internal ISP PLL for the required output frequency.
0423  * Locking: called with s5k6aa.lock mutex held.
0424  */
0425 static int s5k6aa_configure_pixel_clocks(struct s5k6aa *s5k6aa)
0426 {
0427     struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
0428     unsigned long fmclk = s5k6aa->mclk_frequency / 1000;
0429     u16 status;
0430     int ret;
0431 
0432     if (WARN(fmclk < MIN_MCLK_FREQ_KHZ || fmclk > MAX_MCLK_FREQ_KHZ,
0433          "Invalid clock frequency: %ld\n", fmclk))
0434         return -EINVAL;
0435 
0436     s5k6aa->pclk_fmin = PCLK_FREQ_MIN;
0437     s5k6aa->pclk_fmax = PCLK_FREQ_MAX;
0438     s5k6aa->clk_fop = SYS_PLL_OUT_FREQ;
0439 
0440     /* External input clock frequency in kHz */
0441     ret = s5k6aa_write(c, REG_I_INCLK_FREQ_H, fmclk >> 16);
0442     if (!ret)
0443         ret = s5k6aa_write(c, REG_I_INCLK_FREQ_L, fmclk & 0xFFFF);
0444     if (!ret)
0445         ret = s5k6aa_write(c, REG_I_USE_NPVI_CLOCKS, 1);
0446     /* Internal PLL frequency */
0447     if (!ret)
0448         ret = s5k6aa_write(c, REG_I_OPCLK_4KHZ(0), s5k6aa->clk_fop);
0449     if (!ret)
0450         ret = s5k6aa_write(c, REG_I_MIN_OUTRATE_4KHZ(0),
0451                    s5k6aa->pclk_fmin);
0452     if (!ret)
0453         ret = s5k6aa_write(c, REG_I_MAX_OUTRATE_4KHZ(0),
0454                    s5k6aa->pclk_fmax);
0455     if (!ret)
0456         ret = s5k6aa_write(c, REG_I_INIT_PARAMS_UPDATED, 1);
0457     if (!ret)
0458         ret = s5k6aa_read(c, REG_I_ERROR_INFO, &status);
0459 
0460     return ret ? ret : (status ? -EINVAL : 0);
0461 }
0462 
0463 /* Set horizontal and vertical image flipping */
0464 static int s5k6aa_set_mirror(struct s5k6aa *s5k6aa, int horiz_flip)
0465 {
0466     struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
0467     int index = s5k6aa->preset->index;
0468 
0469     unsigned int vflip = s5k6aa->ctrls.vflip->val ^ s5k6aa->inv_vflip;
0470     unsigned int flip = (horiz_flip ^ s5k6aa->inv_hflip) | (vflip << 1);
0471 
0472     return s5k6aa_write(client, REG_P_PREV_MIRROR(index), flip);
0473 }
0474 
0475 /* Configure auto/manual white balance and R/G/B gains */
0476 static int s5k6aa_set_awb(struct s5k6aa *s5k6aa, int awb)
0477 {
0478     struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
0479     struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls;
0480     u16 reg;
0481 
0482     int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &reg);
0483 
0484     if (!ret && !awb) {
0485         ret = s5k6aa_write(c, REG_SF_RGAIN, ctrls->gain_red->val);
0486         if (!ret)
0487             ret = s5k6aa_write(c, REG_SF_RGAIN_CHG, 1);
0488         if (ret)
0489             return ret;
0490 
0491         ret = s5k6aa_write(c, REG_SF_GGAIN, ctrls->gain_green->val);
0492         if (!ret)
0493             ret = s5k6aa_write(c, REG_SF_GGAIN_CHG, 1);
0494         if (ret)
0495             return ret;
0496 
0497         ret = s5k6aa_write(c, REG_SF_BGAIN, ctrls->gain_blue->val);
0498         if (!ret)
0499             ret = s5k6aa_write(c, REG_SF_BGAIN_CHG, 1);
0500     }
0501     if (!ret) {
0502         reg = awb ? reg | AALG_WB_EN_MASK : reg & ~AALG_WB_EN_MASK;
0503         ret = s5k6aa_write(c, REG_DBG_AUTOALG_EN, reg);
0504     }
0505 
0506     return ret;
0507 }
0508 
0509 /* Program FW with exposure time, 'exposure' in us units */
0510 static int s5k6aa_set_user_exposure(struct i2c_client *client, int exposure)
0511 {
0512     unsigned int time = exposure / 10;
0513 
0514     int ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_L, time & 0xffff);
0515     if (!ret)
0516         ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_H, time >> 16);
0517     if (ret)
0518         return ret;
0519     return s5k6aa_write(client, REG_SF_USR_EXPOSURE_CHG, 1);
0520 }
0521 
0522 static int s5k6aa_set_user_gain(struct i2c_client *client, int gain)
0523 {
0524     int ret = s5k6aa_write(client, REG_SF_USR_TOT_GAIN, gain);
0525     if (ret)
0526         return ret;
0527     return s5k6aa_write(client, REG_SF_USR_TOT_GAIN_CHG, 1);
0528 }
0529 
0530 /* Set auto/manual exposure and total gain */
0531 static int s5k6aa_set_auto_exposure(struct s5k6aa *s5k6aa, int value)
0532 {
0533     struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
0534     unsigned int exp_time = s5k6aa->ctrls.exposure->val;
0535     u16 auto_alg;
0536 
0537     int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &auto_alg);
0538     if (ret)
0539         return ret;
0540 
0541     v4l2_dbg(1, debug, c, "man_exp: %d, auto_exp: %d, a_alg: 0x%x\n",
0542          exp_time, value, auto_alg);
0543 
0544     if (value == V4L2_EXPOSURE_AUTO) {
0545         auto_alg |= AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK;
0546     } else {
0547         ret = s5k6aa_set_user_exposure(c, exp_time);
0548         if (ret)
0549             return ret;
0550         ret = s5k6aa_set_user_gain(c, s5k6aa->ctrls.gain->val);
0551         if (ret)
0552             return ret;
0553         auto_alg &= ~(AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK);
0554     }
0555 
0556     return s5k6aa_write(c, REG_DBG_AUTOALG_EN, auto_alg);
0557 }
0558 
0559 static int s5k6aa_set_anti_flicker(struct s5k6aa *s5k6aa, int value)
0560 {
0561     struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
0562     u16 auto_alg;
0563     int ret;
0564 
0565     ret = s5k6aa_read(client, REG_DBG_AUTOALG_EN, &auto_alg);
0566     if (ret)
0567         return ret;
0568 
0569     if (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) {
0570         auto_alg |= AALG_FLICKER_EN_MASK;
0571     } else {
0572         auto_alg &= ~AALG_FLICKER_EN_MASK;
0573         /* The V4L2_CID_LINE_FREQUENCY control values match
0574          * the register values */
0575         ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT, value);
0576         if (ret)
0577             return ret;
0578         ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT_CHG, 1);
0579         if (ret)
0580             return ret;
0581     }
0582 
0583     return s5k6aa_write(client, REG_DBG_AUTOALG_EN, auto_alg);
0584 }
0585 
0586 static int s5k6aa_set_colorfx(struct s5k6aa *s5k6aa, int val)
0587 {
0588     struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
0589     static const struct v4l2_control colorfx[] = {
0590         { V4L2_COLORFX_NONE,     0 },
0591         { V4L2_COLORFX_BW,   1 },
0592         { V4L2_COLORFX_NEGATIVE, 2 },
0593         { V4L2_COLORFX_SEPIA,    3 },
0594         { V4L2_COLORFX_SKY_BLUE, 4 },
0595         { V4L2_COLORFX_SKETCH,   5 },
0596     };
0597     int i;
0598 
0599     for (i = 0; i < ARRAY_SIZE(colorfx); i++) {
0600         if (colorfx[i].id == val)
0601             return s5k6aa_write(client, REG_G_SPEC_EFFECTS,
0602                         colorfx[i].value);
0603     }
0604     return -EINVAL;
0605 }
0606 
0607 static int s5k6aa_preview_config_status(struct i2c_client *client)
0608 {
0609     u16 error = 0;
0610     int ret = s5k6aa_read(client, REG_G_PREV_CFG_ERROR, &error);
0611 
0612     v4l2_dbg(1, debug, client, "error: 0x%x (%d)\n", error, ret);
0613     return ret ? ret : (error ? -EINVAL : 0);
0614 }
0615 
0616 static int s5k6aa_get_pixfmt_index(struct s5k6aa *s5k6aa,
0617                    struct v4l2_mbus_framefmt *mf)
0618 {
0619     unsigned int i;
0620 
0621     for (i = 0; i < ARRAY_SIZE(s5k6aa_formats); i++)
0622         if (mf->colorspace == s5k6aa_formats[i].colorspace &&
0623             mf->code == s5k6aa_formats[i].code)
0624             return i;
0625     return 0;
0626 }
0627 
0628 static int s5k6aa_set_output_framefmt(struct s5k6aa *s5k6aa,
0629                       struct s5k6aa_preset *preset)
0630 {
0631     struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
0632     int fmt_index = s5k6aa_get_pixfmt_index(s5k6aa, &preset->mbus_fmt);
0633     int ret;
0634 
0635     ret = s5k6aa_write(client, REG_P_OUT_WIDTH(preset->index),
0636                preset->mbus_fmt.width);
0637     if (!ret)
0638         ret = s5k6aa_write(client, REG_P_OUT_HEIGHT(preset->index),
0639                    preset->mbus_fmt.height);
0640     if (!ret)
0641         ret = s5k6aa_write(client, REG_P_FMT(preset->index),
0642                    s5k6aa_formats[fmt_index].reg_p_fmt);
0643     return ret;
0644 }
0645 
0646 static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa)
0647 {
0648     struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd);
0649     struct v4l2_rect *r = &s5k6aa->ccd_rect;
0650     int ret;
0651 
0652     ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width);
0653     if (!ret)
0654         ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height);
0655     if (!ret)
0656         ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left);
0657     if (!ret)
0658         ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top);
0659     if (!ret)
0660         ret = s5k6aa_write(c, REG_G_INPUTS_CHANGE_REQ, 1);
0661     if (!ret)
0662         s5k6aa->apply_crop = 0;
0663 
0664     return ret;
0665 }
0666 
0667 /**
0668  * s5k6aa_configure_video_bus - configure the video output interface
0669  * @s5k6aa: pointer to &struct s5k6aa describing the device
0670  * @bus_type: video bus type: parallel or MIPI-CSI
0671  * @nlanes: number of MIPI lanes to be used (MIPI-CSI only)
0672  *
0673  * Note: Only parallel bus operation has been tested.
0674  */
0675 static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa,
0676                       enum v4l2_mbus_type bus_type, int nlanes)
0677 {
0678     struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
0679     u16 cfg = 0;
0680     int ret;
0681 
0682     /*
0683      * TODO: The sensor is supposed to support BT.601 and BT.656
0684      * but there is nothing indicating how to switch between both
0685      * in the datasheet. For now default BT.601 interface is assumed.
0686      */
0687     if (bus_type == V4L2_MBUS_CSI2_DPHY)
0688         cfg = nlanes;
0689     else if (bus_type != V4L2_MBUS_PARALLEL)
0690         return -EINVAL;
0691 
0692     ret = s5k6aa_write(client, REG_OIF_EN_MIPI_LANES, cfg);
0693     if (ret)
0694         return ret;
0695     return s5k6aa_write(client, REG_OIF_CFG_CHG, 1);
0696 }
0697 
0698 /* This function should be called when switching to new user configuration set*/
0699 static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout,
0700                   int cid)
0701 {
0702     unsigned long end = jiffies + msecs_to_jiffies(timeout);
0703     u16 reg = 1;
0704     int ret;
0705 
0706     ret = s5k6aa_write(client, REG_G_ACTIVE_PREV_CFG, cid);
0707     if (!ret)
0708         ret = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
0709     if (!ret)
0710         ret = s5k6aa_write(client, REG_G_NEW_CFG_SYNC, 1);
0711     if (timeout == 0)
0712         return ret;
0713 
0714     while (ret >= 0 && time_is_after_jiffies(end)) {
0715         ret = s5k6aa_read(client, REG_G_NEW_CFG_SYNC, &reg);
0716         if (!reg)
0717             return 0;
0718         usleep_range(1000, 5000);
0719     }
0720     return ret ? ret : -ETIMEDOUT;
0721 }
0722 
0723 /**
0724  * s5k6aa_set_prev_config - write user preview register set
0725  * @s5k6aa: pointer to &struct s5k6aa describing the device
0726  * @preset: s5kaa preset to be applied
0727  *
0728  * Configure output resolution and color format, pixel clock
0729  * frequency range, device frame rate type and frame period range.
0730  */
0731 static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa,
0732                   struct s5k6aa_preset *preset)
0733 {
0734     struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
0735     int idx = preset->index;
0736     u16 frame_rate_q;
0737     int ret;
0738 
0739     if (s5k6aa->fiv->reg_fr_time >= S5K6AA_MAX_HIGHRES_FR_TIME)
0740         frame_rate_q = FR_RATE_Q_BEST_FRRATE;
0741     else
0742         frame_rate_q = FR_RATE_Q_BEST_QUALITY;
0743 
0744     ret = s5k6aa_set_output_framefmt(s5k6aa, preset);
0745     if (!ret)
0746         ret = s5k6aa_write(client, REG_P_MAX_OUT_RATE(idx),
0747                    s5k6aa->pclk_fmax);
0748     if (!ret)
0749         ret = s5k6aa_write(client, REG_P_MIN_OUT_RATE(idx),
0750                    s5k6aa->pclk_fmin);
0751     if (!ret)
0752         ret = s5k6aa_write(client, REG_P_CLK_INDEX(idx),
0753                    preset->clk_id);
0754     if (!ret)
0755         ret = s5k6aa_write(client, REG_P_FR_RATE_TYPE(idx),
0756                    FR_RATE_DYNAMIC);
0757     if (!ret)
0758         ret = s5k6aa_write(client, REG_P_FR_RATE_Q_TYPE(idx),
0759                    frame_rate_q);
0760     if (!ret)
0761         ret = s5k6aa_write(client, REG_P_MAX_FR_TIME(idx),
0762                    s5k6aa->fiv->reg_fr_time + 33);
0763     if (!ret)
0764         ret = s5k6aa_write(client, REG_P_MIN_FR_TIME(idx),
0765                    s5k6aa->fiv->reg_fr_time - 33);
0766     if (!ret)
0767         ret = s5k6aa_new_config_sync(client, 250, idx);
0768     if (!ret)
0769         ret = s5k6aa_preview_config_status(client);
0770     if (!ret)
0771         s5k6aa->apply_cfg = 0;
0772 
0773     v4l2_dbg(1, debug, client, "Frame interval: %d +/- 3.3ms. (%d)\n",
0774          s5k6aa->fiv->reg_fr_time, ret);
0775     return ret;
0776 }
0777 
0778 /**
0779  * s5k6aa_initialize_isp - basic ISP MCU initialization
0780  * @sd: pointer to V4L2 sub-device descriptor
0781  *
0782  * Configure AHB addresses for registers read/write; configure PLLs for
0783  * required output pixel clock. The ISP power supply needs to be already
0784  * enabled, with an optional H/W reset.
0785  * Locking: called with s5k6aa.lock mutex held.
0786  */
0787 static int s5k6aa_initialize_isp(struct v4l2_subdev *sd)
0788 {
0789     struct i2c_client *client = v4l2_get_subdevdata(sd);
0790     struct s5k6aa *s5k6aa = to_s5k6aa(sd);
0791     int ret;
0792 
0793     s5k6aa->apply_crop = 1;
0794     s5k6aa->apply_cfg = 1;
0795     msleep(100);
0796 
0797     ret = s5k6aa_set_ahb_address(client);
0798     if (ret)
0799         return ret;
0800     ret = s5k6aa_configure_video_bus(s5k6aa, s5k6aa->bus_type,
0801                      s5k6aa->mipi_lanes);
0802     if (ret)
0803         return ret;
0804     ret = s5k6aa_write_array(sd, s5k6aa_analog_config);
0805     if (ret)
0806         return ret;
0807     msleep(20);
0808 
0809     return s5k6aa_configure_pixel_clocks(s5k6aa);
0810 }
0811 
0812 static int s5k6aa_gpio_set_value(struct s5k6aa *priv, int id, u32 val)
0813 {
0814     if (!gpio_is_valid(priv->gpio[id].gpio))
0815         return 0;
0816     gpio_set_value(priv->gpio[id].gpio, !!val);
0817     return 1;
0818 }
0819 
0820 static int s5k6aa_gpio_assert(struct s5k6aa *priv, int id)
0821 {
0822     return s5k6aa_gpio_set_value(priv, id, priv->gpio[id].level);
0823 }
0824 
0825 static int s5k6aa_gpio_deassert(struct s5k6aa *priv, int id)
0826 {
0827     return s5k6aa_gpio_set_value(priv, id, !priv->gpio[id].level);
0828 }
0829 
0830 static int __s5k6aa_power_on(struct s5k6aa *s5k6aa)
0831 {
0832     int ret;
0833 
0834     ret = regulator_bulk_enable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
0835     if (ret)
0836         return ret;
0837     if (s5k6aa_gpio_deassert(s5k6aa, STBY))
0838         usleep_range(150, 200);
0839 
0840     if (s5k6aa->s_power)
0841         ret = s5k6aa->s_power(1);
0842     usleep_range(4000, 5000);
0843 
0844     if (s5k6aa_gpio_deassert(s5k6aa, RSET))
0845         msleep(20);
0846 
0847     return ret;
0848 }
0849 
0850 static int __s5k6aa_power_off(struct s5k6aa *s5k6aa)
0851 {
0852     int ret;
0853 
0854     if (s5k6aa_gpio_assert(s5k6aa, RSET))
0855         usleep_range(100, 150);
0856 
0857     if (s5k6aa->s_power) {
0858         ret = s5k6aa->s_power(0);
0859         if (ret)
0860             return ret;
0861     }
0862     if (s5k6aa_gpio_assert(s5k6aa, STBY))
0863         usleep_range(50, 100);
0864     s5k6aa->streaming = 0;
0865 
0866     return regulator_bulk_disable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
0867 }
0868 
0869 /*
0870  * V4L2 subdev core and video operations
0871  */
0872 static int s5k6aa_set_power(struct v4l2_subdev *sd, int on)
0873 {
0874     struct s5k6aa *s5k6aa = to_s5k6aa(sd);
0875     int ret = 0;
0876 
0877     mutex_lock(&s5k6aa->lock);
0878 
0879     if (s5k6aa->power == !on) {
0880         if (on) {
0881             ret = __s5k6aa_power_on(s5k6aa);
0882             if (!ret)
0883                 ret = s5k6aa_initialize_isp(sd);
0884         } else {
0885             ret = __s5k6aa_power_off(s5k6aa);
0886         }
0887 
0888         if (!ret)
0889             s5k6aa->power += on ? 1 : -1;
0890     }
0891 
0892     mutex_unlock(&s5k6aa->lock);
0893 
0894     if (!on || ret || s5k6aa->power != 1)
0895         return ret;
0896 
0897     return v4l2_ctrl_handler_setup(sd->ctrl_handler);
0898 }
0899 
0900 static int __s5k6aa_stream(struct s5k6aa *s5k6aa, int enable)
0901 {
0902     struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
0903     int ret = 0;
0904 
0905     ret = s5k6aa_write(client, REG_G_ENABLE_PREV, enable);
0906     if (!ret)
0907         ret = s5k6aa_write(client, REG_G_ENABLE_PREV_CHG, 1);
0908     if (!ret)
0909         s5k6aa->streaming = enable;
0910 
0911     return ret;
0912 }
0913 
0914 static int s5k6aa_s_stream(struct v4l2_subdev *sd, int on)
0915 {
0916     struct s5k6aa *s5k6aa = to_s5k6aa(sd);
0917     int ret = 0;
0918 
0919     mutex_lock(&s5k6aa->lock);
0920 
0921     if (s5k6aa->streaming == !on) {
0922         if (!ret && s5k6aa->apply_cfg)
0923             ret = s5k6aa_set_prev_config(s5k6aa, s5k6aa->preset);
0924         if (s5k6aa->apply_crop)
0925             ret = s5k6aa_set_input_params(s5k6aa);
0926         if (!ret)
0927             ret = __s5k6aa_stream(s5k6aa, !!on);
0928     }
0929     mutex_unlock(&s5k6aa->lock);
0930 
0931     return ret;
0932 }
0933 
0934 static int s5k6aa_g_frame_interval(struct v4l2_subdev *sd,
0935                    struct v4l2_subdev_frame_interval *fi)
0936 {
0937     struct s5k6aa *s5k6aa = to_s5k6aa(sd);
0938 
0939     mutex_lock(&s5k6aa->lock);
0940     fi->interval = s5k6aa->fiv->interval;
0941     mutex_unlock(&s5k6aa->lock);
0942 
0943     return 0;
0944 }
0945 
0946 static int __s5k6aa_set_frame_interval(struct s5k6aa *s5k6aa,
0947                        struct v4l2_subdev_frame_interval *fi)
0948 {
0949     struct v4l2_mbus_framefmt *mbus_fmt = &s5k6aa->preset->mbus_fmt;
0950     const struct s5k6aa_interval *fiv = &s5k6aa_intervals[0];
0951     unsigned int err, min_err = UINT_MAX;
0952     unsigned int i, fr_time;
0953 
0954     if (fi->interval.denominator == 0)
0955         return -EINVAL;
0956 
0957     fr_time = fi->interval.numerator * 10000 / fi->interval.denominator;
0958 
0959     for (i = 0; i < ARRAY_SIZE(s5k6aa_intervals); i++) {
0960         const struct s5k6aa_interval *iv = &s5k6aa_intervals[i];
0961 
0962         if (mbus_fmt->width > iv->size.width ||
0963             mbus_fmt->height > iv->size.height)
0964             continue;
0965 
0966         err = abs(iv->reg_fr_time - fr_time);
0967         if (err < min_err) {
0968             fiv = iv;
0969             min_err = err;
0970         }
0971     }
0972     s5k6aa->fiv = fiv;
0973 
0974     v4l2_dbg(1, debug, &s5k6aa->sd, "Changed frame interval to %d us\n",
0975          fiv->reg_fr_time * 100);
0976     return 0;
0977 }
0978 
0979 static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd,
0980                    struct v4l2_subdev_frame_interval *fi)
0981 {
0982     struct s5k6aa *s5k6aa = to_s5k6aa(sd);
0983     int ret;
0984 
0985     v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n",
0986          fi->interval.numerator, fi->interval.denominator);
0987 
0988     mutex_lock(&s5k6aa->lock);
0989     ret = __s5k6aa_set_frame_interval(s5k6aa, fi);
0990     s5k6aa->apply_cfg = 1;
0991 
0992     mutex_unlock(&s5k6aa->lock);
0993     return ret;
0994 }
0995 
0996 /*
0997  * V4L2 subdev pad level and video operations
0998  */
0999 static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
1000                   struct v4l2_subdev_state *sd_state,
1001                   struct v4l2_subdev_frame_interval_enum *fie)
1002 {
1003     struct s5k6aa *s5k6aa = to_s5k6aa(sd);
1004     const struct s5k6aa_interval *fi;
1005     int ret = 0;
1006 
1007     if (fie->index >= ARRAY_SIZE(s5k6aa_intervals))
1008         return -EINVAL;
1009 
1010     v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN,
1011                   S5K6AA_WIN_WIDTH_MAX, 1,
1012                   &fie->height, S5K6AA_WIN_HEIGHT_MIN,
1013                   S5K6AA_WIN_HEIGHT_MAX, 1, 0);
1014 
1015     mutex_lock(&s5k6aa->lock);
1016     fi = &s5k6aa_intervals[fie->index];
1017     if (fie->width > fi->size.width || fie->height > fi->size.height)
1018         ret = -EINVAL;
1019     else
1020         fie->interval = fi->interval;
1021     mutex_unlock(&s5k6aa->lock);
1022 
1023     return ret;
1024 }
1025 
1026 static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd,
1027                  struct v4l2_subdev_state *sd_state,
1028                  struct v4l2_subdev_mbus_code_enum *code)
1029 {
1030     if (code->index >= ARRAY_SIZE(s5k6aa_formats))
1031         return -EINVAL;
1032 
1033     code->code = s5k6aa_formats[code->index].code;
1034     return 0;
1035 }
1036 
1037 static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd,
1038                   struct v4l2_subdev_state *sd_state,
1039                   struct v4l2_subdev_frame_size_enum *fse)
1040 {
1041     int i = ARRAY_SIZE(s5k6aa_formats);
1042 
1043     if (fse->index > 0)
1044         return -EINVAL;
1045 
1046     while (--i)
1047         if (fse->code == s5k6aa_formats[i].code)
1048             break;
1049 
1050     fse->code = s5k6aa_formats[i].code;
1051     fse->min_width  = S5K6AA_WIN_WIDTH_MIN;
1052     fse->max_width  = S5K6AA_WIN_WIDTH_MAX;
1053     fse->max_height = S5K6AA_WIN_HEIGHT_MIN;
1054     fse->min_height = S5K6AA_WIN_HEIGHT_MAX;
1055 
1056     return 0;
1057 }
1058 
1059 static struct v4l2_rect *
1060 __s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa,
1061                struct v4l2_subdev_state *sd_state,
1062                enum v4l2_subdev_format_whence which)
1063 {
1064     if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
1065         return &s5k6aa->ccd_rect;
1066 
1067     WARN_ON(which != V4L2_SUBDEV_FORMAT_TRY);
1068     return v4l2_subdev_get_try_crop(&s5k6aa->sd, sd_state, 0);
1069 }
1070 
1071 static void s5k6aa_try_format(struct s5k6aa *s5k6aa,
1072                   struct v4l2_mbus_framefmt *mf)
1073 {
1074     unsigned int index;
1075 
1076     v4l_bound_align_image(&mf->width, S5K6AA_WIN_WIDTH_MIN,
1077                   S5K6AA_WIN_WIDTH_MAX, 1,
1078                   &mf->height, S5K6AA_WIN_HEIGHT_MIN,
1079                   S5K6AA_WIN_HEIGHT_MAX, 1, 0);
1080 
1081     if (mf->colorspace != V4L2_COLORSPACE_JPEG &&
1082         mf->colorspace != V4L2_COLORSPACE_REC709)
1083         mf->colorspace = V4L2_COLORSPACE_JPEG;
1084 
1085     index = s5k6aa_get_pixfmt_index(s5k6aa, mf);
1086 
1087     mf->colorspace  = s5k6aa_formats[index].colorspace;
1088     mf->code    = s5k6aa_formats[index].code;
1089     mf->field   = V4L2_FIELD_NONE;
1090 }
1091 
1092 static int s5k6aa_get_fmt(struct v4l2_subdev *sd,
1093               struct v4l2_subdev_state *sd_state,
1094               struct v4l2_subdev_format *fmt)
1095 {
1096     struct s5k6aa *s5k6aa = to_s5k6aa(sd);
1097     struct v4l2_mbus_framefmt *mf;
1098 
1099     memset(fmt->reserved, 0, sizeof(fmt->reserved));
1100 
1101     if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1102         mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
1103         fmt->format = *mf;
1104         return 0;
1105     }
1106 
1107     mutex_lock(&s5k6aa->lock);
1108     fmt->format = s5k6aa->preset->mbus_fmt;
1109     mutex_unlock(&s5k6aa->lock);
1110 
1111     return 0;
1112 }
1113 
1114 static int s5k6aa_set_fmt(struct v4l2_subdev *sd,
1115               struct v4l2_subdev_state *sd_state,
1116               struct v4l2_subdev_format *fmt)
1117 {
1118     struct s5k6aa *s5k6aa = to_s5k6aa(sd);
1119     struct s5k6aa_preset *preset = s5k6aa->preset;
1120     struct v4l2_mbus_framefmt *mf;
1121     struct v4l2_rect *crop;
1122     int ret = 0;
1123 
1124     mutex_lock(&s5k6aa->lock);
1125     s5k6aa_try_format(s5k6aa, &fmt->format);
1126 
1127     if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1128         mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
1129         crop = v4l2_subdev_get_try_crop(sd, sd_state, 0);
1130     } else {
1131         if (s5k6aa->streaming) {
1132             ret = -EBUSY;
1133         } else {
1134             mf = &preset->mbus_fmt;
1135             crop = &s5k6aa->ccd_rect;
1136             s5k6aa->apply_cfg = 1;
1137         }
1138     }
1139 
1140     if (ret == 0) {
1141         struct v4l2_subdev_frame_interval fiv = {
1142             .interval = {0, 1}
1143         };
1144 
1145         *mf = fmt->format;
1146         /*
1147          * Make sure the crop window is valid, i.e. its size is
1148          * greater than the output window, as the ISP supports
1149          * only down-scaling.
1150          */
1151         crop->width = clamp_t(unsigned int, crop->width, mf->width,
1152                       S5K6AA_WIN_WIDTH_MAX);
1153         crop->height = clamp_t(unsigned int, crop->height, mf->height,
1154                        S5K6AA_WIN_HEIGHT_MAX);
1155         crop->left = clamp_t(unsigned int, crop->left, 0,
1156                      S5K6AA_WIN_WIDTH_MAX - crop->width);
1157         crop->top  = clamp_t(unsigned int, crop->top, 0,
1158                      S5K6AA_WIN_HEIGHT_MAX - crop->height);
1159 
1160         /* Reset to minimum possible frame interval */
1161         ret = __s5k6aa_set_frame_interval(s5k6aa, &fiv);
1162     }
1163     mutex_unlock(&s5k6aa->lock);
1164 
1165     return ret;
1166 }
1167 
1168 static int s5k6aa_get_selection(struct v4l2_subdev *sd,
1169                 struct v4l2_subdev_state *sd_state,
1170                 struct v4l2_subdev_selection *sel)
1171 {
1172     struct s5k6aa *s5k6aa = to_s5k6aa(sd);
1173     struct v4l2_rect *rect;
1174 
1175     if (sel->target != V4L2_SEL_TGT_CROP)
1176         return -EINVAL;
1177 
1178     memset(sel->reserved, 0, sizeof(sel->reserved));
1179 
1180     mutex_lock(&s5k6aa->lock);
1181     rect = __s5k6aa_get_crop_rect(s5k6aa, sd_state, sel->which);
1182     sel->r = *rect;
1183     mutex_unlock(&s5k6aa->lock);
1184 
1185     v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n",
1186          rect->left, rect->top, rect->width, rect->height);
1187 
1188     return 0;
1189 }
1190 
1191 static int s5k6aa_set_selection(struct v4l2_subdev *sd,
1192                 struct v4l2_subdev_state *sd_state,
1193                 struct v4l2_subdev_selection *sel)
1194 {
1195     struct s5k6aa *s5k6aa = to_s5k6aa(sd);
1196     struct v4l2_mbus_framefmt *mf;
1197     unsigned int max_x, max_y;
1198     struct v4l2_rect *crop_r;
1199 
1200     if (sel->target != V4L2_SEL_TGT_CROP)
1201         return -EINVAL;
1202 
1203     mutex_lock(&s5k6aa->lock);
1204     crop_r = __s5k6aa_get_crop_rect(s5k6aa, sd_state, sel->which);
1205 
1206     if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1207         mf = &s5k6aa->preset->mbus_fmt;
1208         s5k6aa->apply_crop = 1;
1209     } else {
1210         mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
1211     }
1212     v4l_bound_align_image(&sel->r.width, mf->width,
1213                   S5K6AA_WIN_WIDTH_MAX, 1,
1214                   &sel->r.height, mf->height,
1215                   S5K6AA_WIN_HEIGHT_MAX, 1, 0);
1216 
1217     max_x = (S5K6AA_WIN_WIDTH_MAX - sel->r.width) & ~1;
1218     max_y = (S5K6AA_WIN_HEIGHT_MAX - sel->r.height) & ~1;
1219 
1220     sel->r.left = clamp_t(unsigned int, sel->r.left, 0, max_x);
1221     sel->r.top  = clamp_t(unsigned int, sel->r.top, 0, max_y);
1222 
1223     *crop_r = sel->r;
1224 
1225     mutex_unlock(&s5k6aa->lock);
1226 
1227     v4l2_dbg(1, debug, sd, "Set crop rectangle: (%d,%d)/%dx%d\n",
1228          crop_r->left, crop_r->top, crop_r->width, crop_r->height);
1229 
1230     return 0;
1231 }
1232 
1233 static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = {
1234     .enum_mbus_code     = s5k6aa_enum_mbus_code,
1235     .enum_frame_size    = s5k6aa_enum_frame_size,
1236     .enum_frame_interval    = s5k6aa_enum_frame_interval,
1237     .get_fmt        = s5k6aa_get_fmt,
1238     .set_fmt        = s5k6aa_set_fmt,
1239     .get_selection      = s5k6aa_get_selection,
1240     .set_selection      = s5k6aa_set_selection,
1241 };
1242 
1243 static const struct v4l2_subdev_video_ops s5k6aa_video_ops = {
1244     .g_frame_interval   = s5k6aa_g_frame_interval,
1245     .s_frame_interval   = s5k6aa_s_frame_interval,
1246     .s_stream       = s5k6aa_s_stream,
1247 };
1248 
1249 /*
1250  * V4L2 subdev controls
1251  */
1252 
1253 static int s5k6aa_s_ctrl(struct v4l2_ctrl *ctrl)
1254 {
1255     struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
1256     struct i2c_client *client = v4l2_get_subdevdata(sd);
1257     struct s5k6aa *s5k6aa = to_s5k6aa(sd);
1258     int idx, err = 0;
1259 
1260     v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val);
1261 
1262     mutex_lock(&s5k6aa->lock);
1263     /*
1264      * If the device is not powered up by the host driver do
1265      * not apply any controls to H/W at this time. Instead
1266      * the controls will be restored right after power-up.
1267      */
1268     if (s5k6aa->power == 0)
1269         goto unlock;
1270     idx = s5k6aa->preset->index;
1271 
1272     switch (ctrl->id) {
1273     case V4L2_CID_AUTO_WHITE_BALANCE:
1274         err = s5k6aa_set_awb(s5k6aa, ctrl->val);
1275         break;
1276 
1277     case V4L2_CID_BRIGHTNESS:
1278         err = s5k6aa_write(client, REG_USER_BRIGHTNESS, ctrl->val);
1279         break;
1280 
1281     case V4L2_CID_COLORFX:
1282         err = s5k6aa_set_colorfx(s5k6aa, ctrl->val);
1283         break;
1284 
1285     case V4L2_CID_CONTRAST:
1286         err = s5k6aa_write(client, REG_USER_CONTRAST, ctrl->val);
1287         break;
1288 
1289     case V4L2_CID_EXPOSURE_AUTO:
1290         err = s5k6aa_set_auto_exposure(s5k6aa, ctrl->val);
1291         break;
1292 
1293     case V4L2_CID_HFLIP:
1294         err = s5k6aa_set_mirror(s5k6aa, ctrl->val);
1295         if (err)
1296             break;
1297         err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
1298         break;
1299 
1300     case V4L2_CID_POWER_LINE_FREQUENCY:
1301         err = s5k6aa_set_anti_flicker(s5k6aa, ctrl->val);
1302         break;
1303 
1304     case V4L2_CID_SATURATION:
1305         err = s5k6aa_write(client, REG_USER_SATURATION, ctrl->val);
1306         break;
1307 
1308     case V4L2_CID_SHARPNESS:
1309         err = s5k6aa_write(client, REG_USER_SHARPBLUR, ctrl->val);
1310         break;
1311 
1312     case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
1313         err = s5k6aa_write(client, REG_P_COLORTEMP(idx), ctrl->val);
1314         if (err)
1315             break;
1316         err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1);
1317         break;
1318     }
1319 unlock:
1320     mutex_unlock(&s5k6aa->lock);
1321     return err;
1322 }
1323 
1324 static const struct v4l2_ctrl_ops s5k6aa_ctrl_ops = {
1325     .s_ctrl = s5k6aa_s_ctrl,
1326 };
1327 
1328 static int s5k6aa_log_status(struct v4l2_subdev *sd)
1329 {
1330     v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
1331     return 0;
1332 }
1333 
1334 #define V4L2_CID_RED_GAIN   (V4L2_CTRL_CLASS_CAMERA | 0x1001)
1335 #define V4L2_CID_GREEN_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1002)
1336 #define V4L2_CID_BLUE_GAIN  (V4L2_CTRL_CLASS_CAMERA | 0x1003)
1337 
1338 static const struct v4l2_ctrl_config s5k6aa_ctrls[] = {
1339     {
1340         .ops    = &s5k6aa_ctrl_ops,
1341         .id = V4L2_CID_RED_GAIN,
1342         .type   = V4L2_CTRL_TYPE_INTEGER,
1343         .name   = "Gain, Red",
1344         .min    = 0,
1345         .max    = 256,
1346         .def    = 127,
1347         .step   = 1,
1348     }, {
1349         .ops    = &s5k6aa_ctrl_ops,
1350         .id = V4L2_CID_GREEN_GAIN,
1351         .type   = V4L2_CTRL_TYPE_INTEGER,
1352         .name   = "Gain, Green",
1353         .min    = 0,
1354         .max    = 256,
1355         .def    = 127,
1356         .step   = 1,
1357     }, {
1358         .ops    = &s5k6aa_ctrl_ops,
1359         .id = V4L2_CID_BLUE_GAIN,
1360         .type   = V4L2_CTRL_TYPE_INTEGER,
1361         .name   = "Gain, Blue",
1362         .min    = 0,
1363         .max    = 256,
1364         .def    = 127,
1365         .step   = 1,
1366     },
1367 };
1368 
1369 static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa)
1370 {
1371     const struct v4l2_ctrl_ops *ops = &s5k6aa_ctrl_ops;
1372     struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls;
1373     struct v4l2_ctrl_handler *hdl = &ctrls->handler;
1374 
1375     int ret = v4l2_ctrl_handler_init(hdl, 16);
1376     if (ret)
1377         return ret;
1378     /* Auto white balance cluster */
1379     ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE,
1380                        0, 1, 1, 1);
1381     ctrls->gain_red = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[0], NULL);
1382     ctrls->gain_green = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[1], NULL);
1383     ctrls->gain_blue = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[2], NULL);
1384     v4l2_ctrl_auto_cluster(4, &ctrls->awb, 0, false);
1385 
1386     ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
1387     ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
1388     v4l2_ctrl_cluster(2, &ctrls->hflip);
1389 
1390     ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
1391                 V4L2_CID_EXPOSURE_AUTO,
1392                 V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO);
1393     /* Exposure time: x 1 us */
1394     ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
1395                         0, 6000000U, 1, 100000U);
1396     /* Total gain: 256 <=> 1x */
1397     ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
1398                     0, 256, 1, 256);
1399     v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false);
1400 
1401     v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY,
1402                    V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
1403                    V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
1404 
1405     v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX,
1406                    V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE);
1407 
1408     v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE,
1409               0, 256, 1, 0);
1410 
1411     v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0);
1412     v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0);
1413     v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0);
1414     v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0);
1415 
1416     if (hdl->error) {
1417         ret = hdl->error;
1418         v4l2_ctrl_handler_free(hdl);
1419         return ret;
1420     }
1421 
1422     s5k6aa->sd.ctrl_handler = hdl;
1423     return 0;
1424 }
1425 
1426 /*
1427  * V4L2 subdev internal operations
1428  */
1429 static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
1430 {
1431     struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd,
1432                                        fh->state,
1433                                        0);
1434     struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
1435 
1436     format->colorspace = s5k6aa_formats[0].colorspace;
1437     format->code = s5k6aa_formats[0].code;
1438     format->width = S5K6AA_OUT_WIDTH_DEF;
1439     format->height = S5K6AA_OUT_HEIGHT_DEF;
1440     format->field = V4L2_FIELD_NONE;
1441 
1442     crop->width = S5K6AA_WIN_WIDTH_MAX;
1443     crop->height = S5K6AA_WIN_HEIGHT_MAX;
1444     crop->left = 0;
1445     crop->top = 0;
1446 
1447     return 0;
1448 }
1449 
1450 static int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa)
1451 {
1452     struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
1453     u16 api_ver = 0, fw_rev = 0;
1454 
1455     int ret = s5k6aa_set_ahb_address(client);
1456 
1457     if (!ret)
1458         ret = s5k6aa_read(client, REG_FW_APIVER, &api_ver);
1459     if (!ret)
1460         ret = s5k6aa_read(client, REG_FW_REVISION, &fw_rev);
1461     if (ret) {
1462         v4l2_err(&s5k6aa->sd, "FW revision check failed!\n");
1463         return ret;
1464     }
1465 
1466     v4l2_info(&s5k6aa->sd, "FW API ver.: 0x%X, FW rev.: 0x%X\n",
1467           api_ver, fw_rev);
1468 
1469     return api_ver == S5K6AAFX_FW_APIVER ? 0 : -ENODEV;
1470 }
1471 
1472 static int s5k6aa_registered(struct v4l2_subdev *sd)
1473 {
1474     struct s5k6aa *s5k6aa = to_s5k6aa(sd);
1475     int ret;
1476 
1477     mutex_lock(&s5k6aa->lock);
1478     ret = __s5k6aa_power_on(s5k6aa);
1479     if (!ret) {
1480         msleep(100);
1481         ret = s5k6aa_check_fw_revision(s5k6aa);
1482         __s5k6aa_power_off(s5k6aa);
1483     }
1484     mutex_unlock(&s5k6aa->lock);
1485 
1486     return ret;
1487 }
1488 
1489 static const struct v4l2_subdev_internal_ops s5k6aa_subdev_internal_ops = {
1490     .registered = s5k6aa_registered,
1491     .open = s5k6aa_open,
1492 };
1493 
1494 static const struct v4l2_subdev_core_ops s5k6aa_core_ops = {
1495     .s_power = s5k6aa_set_power,
1496     .log_status = s5k6aa_log_status,
1497 };
1498 
1499 static const struct v4l2_subdev_ops s5k6aa_subdev_ops = {
1500     .core = &s5k6aa_core_ops,
1501     .pad = &s5k6aa_pad_ops,
1502     .video = &s5k6aa_video_ops,
1503 };
1504 
1505 /*
1506  * GPIO setup
1507  */
1508 
1509 static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
1510                   const struct s5k6aa_platform_data *pdata)
1511 {
1512     struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
1513     const struct s5k6aa_gpio *gpio;
1514     unsigned long flags;
1515     int ret;
1516 
1517     s5k6aa->gpio[STBY].gpio = -EINVAL;
1518     s5k6aa->gpio[RSET].gpio  = -EINVAL;
1519 
1520     gpio = &pdata->gpio_stby;
1521     if (gpio_is_valid(gpio->gpio)) {
1522         flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
1523               | GPIOF_EXPORT;
1524         ret = devm_gpio_request_one(&client->dev, gpio->gpio, flags,
1525                         "S5K6AA_STBY");
1526         if (ret < 0)
1527             return ret;
1528 
1529         s5k6aa->gpio[STBY] = *gpio;
1530     }
1531 
1532     gpio = &pdata->gpio_reset;
1533     if (gpio_is_valid(gpio->gpio)) {
1534         flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW)
1535               | GPIOF_EXPORT;
1536         ret = devm_gpio_request_one(&client->dev, gpio->gpio, flags,
1537                         "S5K6AA_RST");
1538         if (ret < 0)
1539             return ret;
1540 
1541         s5k6aa->gpio[RSET] = *gpio;
1542     }
1543 
1544     return 0;
1545 }
1546 
1547 static int s5k6aa_probe(struct i2c_client *client,
1548             const struct i2c_device_id *id)
1549 {
1550     const struct s5k6aa_platform_data *pdata = client->dev.platform_data;
1551     struct v4l2_subdev *sd;
1552     struct s5k6aa *s5k6aa;
1553     int i, ret;
1554 
1555     if (pdata == NULL) {
1556         dev_err(&client->dev, "Platform data not specified\n");
1557         return -EINVAL;
1558     }
1559 
1560     if (pdata->mclk_frequency == 0) {
1561         dev_err(&client->dev, "MCLK frequency not specified\n");
1562         return -EINVAL;
1563     }
1564 
1565     s5k6aa = devm_kzalloc(&client->dev, sizeof(*s5k6aa), GFP_KERNEL);
1566     if (!s5k6aa)
1567         return -ENOMEM;
1568 
1569     mutex_init(&s5k6aa->lock);
1570 
1571     s5k6aa->mclk_frequency = pdata->mclk_frequency;
1572     s5k6aa->bus_type = pdata->bus_type;
1573     s5k6aa->mipi_lanes = pdata->nlanes;
1574     s5k6aa->s_power = pdata->set_power;
1575     s5k6aa->inv_hflip = pdata->horiz_flip;
1576     s5k6aa->inv_vflip = pdata->vert_flip;
1577 
1578     sd = &s5k6aa->sd;
1579     v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops);
1580     /* Static name; NEVER use in new drivers! */
1581     strscpy(sd->name, DRIVER_NAME, sizeof(sd->name));
1582 
1583     sd->internal_ops = &s5k6aa_subdev_internal_ops;
1584     sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1585 
1586     s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE;
1587     sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
1588     ret = media_entity_pads_init(&sd->entity, 1, &s5k6aa->pad);
1589     if (ret)
1590         return ret;
1591 
1592     ret = s5k6aa_configure_gpios(s5k6aa, pdata);
1593     if (ret)
1594         goto out_err;
1595 
1596     for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++)
1597         s5k6aa->supplies[i].supply = s5k6aa_supply_names[i];
1598 
1599     ret = devm_regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES,
1600                  s5k6aa->supplies);
1601     if (ret) {
1602         dev_err(&client->dev, "Failed to get regulators\n");
1603         goto out_err;
1604     }
1605 
1606     ret = s5k6aa_initialize_ctrls(s5k6aa);
1607     if (ret)
1608         goto out_err;
1609 
1610     s5k6aa_presets_data_init(s5k6aa);
1611 
1612     s5k6aa->ccd_rect.width = S5K6AA_WIN_WIDTH_MAX;
1613     s5k6aa->ccd_rect.height = S5K6AA_WIN_HEIGHT_MAX;
1614     s5k6aa->ccd_rect.left = 0;
1615     s5k6aa->ccd_rect.top = 0;
1616 
1617     return 0;
1618 
1619 out_err:
1620     media_entity_cleanup(&s5k6aa->sd.entity);
1621     return ret;
1622 }
1623 
1624 static int s5k6aa_remove(struct i2c_client *client)
1625 {
1626     struct v4l2_subdev *sd = i2c_get_clientdata(client);
1627 
1628     v4l2_device_unregister_subdev(sd);
1629     v4l2_ctrl_handler_free(sd->ctrl_handler);
1630     media_entity_cleanup(&sd->entity);
1631 
1632     return 0;
1633 }
1634 
1635 static const struct i2c_device_id s5k6aa_id[] = {
1636     { DRIVER_NAME, 0 },
1637     { },
1638 };
1639 MODULE_DEVICE_TABLE(i2c, s5k6aa_id);
1640 
1641 
1642 static struct i2c_driver s5k6aa_i2c_driver = {
1643     .driver = {
1644         .name = DRIVER_NAME
1645     },
1646     .probe      = s5k6aa_probe,
1647     .remove     = s5k6aa_remove,
1648     .id_table   = s5k6aa_id,
1649 };
1650 
1651 module_i2c_driver(s5k6aa_i2c_driver);
1652 
1653 MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver");
1654 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1655 MODULE_LICENSE("GPL");