root/drivers/media/i2c/noon010pc30.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_noon010
  2. to_sd
  3. set_i2c_page
  4. cam_i2c_read
  5. cam_i2c_write
  6. noon010_bulk_write_reg
  7. noon010_power_ctrl
  8. noon010_enable_autowhitebalance
  9. noon010_set_flip
  10. noon010_set_params
  11. noon010_try_frame_size
  12. power_enable
  13. power_disable
  14. noon010_s_ctrl
  15. noon010_enum_mbus_code
  16. noon010_get_fmt
  17. noon010_try_fmt
  18. noon010_set_fmt
  19. noon010_base_config
  20. noon010_s_power
  21. noon010_s_stream
  22. noon010_log_status
  23. noon010_open
  24. noon010_detect
  25. noon010_probe
  26. noon010_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Driver for SiliconFile NOON010PC30 CIF (1/11") Image Sensor with ISP
   4  *
   5  * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd.
   6  * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
   7  *
   8  * Initial register configuration based on a driver authored by
   9  * HeungJun Kim <riverful.kim@samsung.com>.
  10  */
  11 
  12 #include <linux/delay.h>
  13 #include <linux/gpio.h>
  14 #include <linux/i2c.h>
  15 #include <linux/slab.h>
  16 #include <linux/regulator/consumer.h>
  17 #include <media/i2c/noon010pc30.h>
  18 #include <linux/videodev2.h>
  19 #include <linux/module.h>
  20 #include <media/v4l2-ctrls.h>
  21 #include <media/v4l2-device.h>
  22 #include <media/v4l2-mediabus.h>
  23 #include <media/v4l2-subdev.h>
  24 
  25 static int debug;
  26 module_param(debug, int, 0644);
  27 MODULE_PARM_DESC(debug, "Enable module debug trace. Set to 1 to enable.");
  28 
  29 #define MODULE_NAME             "NOON010PC30"
  30 
  31 /*
  32  * Register offsets within a page
  33  * b15..b8 - page id, b7..b0 - register address
  34  */
  35 #define POWER_CTRL_REG          0x0001
  36 #define PAGEMODE_REG            0x03
  37 #define DEVICE_ID_REG           0x0004
  38 #define NOON010PC30_ID          0x86
  39 #define VDO_CTL_REG(n)          (0x0010 + (n))
  40 #define SYNC_CTL_REG            0x0012
  41 /* Window size and position */
  42 #define WIN_ROWH_REG            0x0013
  43 #define WIN_ROWL_REG            0x0014
  44 #define WIN_COLH_REG            0x0015
  45 #define WIN_COLL_REG            0x0016
  46 #define WIN_HEIGHTH_REG         0x0017
  47 #define WIN_HEIGHTL_REG         0x0018
  48 #define WIN_WIDTHH_REG          0x0019
  49 #define WIN_WIDTHL_REG          0x001A
  50 #define HBLANKH_REG             0x001B
  51 #define HBLANKL_REG             0x001C
  52 #define VSYNCH_REG              0x001D
  53 #define VSYNCL_REG              0x001E
  54 /* VSYNC control */
  55 #define VS_CTL_REG(n)           (0x00A1 + (n))
  56 /* page 1 */
  57 #define ISP_CTL_REG(n)          (0x0110 + (n))
  58 #define YOFS_REG                0x0119
  59 #define DARK_YOFS_REG           0x011A
  60 #define SAT_CTL_REG             0x0120
  61 #define BSAT_REG                0x0121
  62 #define RSAT_REG                0x0122
  63 /* Color correction */
  64 #define CMC_CTL_REG             0x0130
  65 #define CMC_OFSGH_REG           0x0133
  66 #define CMC_OFSGL_REG           0x0135
  67 #define CMC_SIGN_REG            0x0136
  68 #define CMC_GOFS_REG            0x0137
  69 #define CMC_COEF_REG(n)         (0x0138 + (n))
  70 #define CMC_OFS_REG(n)          (0x0141 + (n))
  71 /* Gamma correction */
  72 #define GMA_CTL_REG             0x0160
  73 #define GMA_COEF_REG(n)         (0x0161 + (n))
  74 /* Lens Shading */
  75 #define LENS_CTRL_REG           0x01D0
  76 #define LENS_XCEN_REG           0x01D1
  77 #define LENS_YCEN_REG           0x01D2
  78 #define LENS_RC_REG             0x01D3
  79 #define LENS_GC_REG             0x01D4
  80 #define LENS_BC_REG             0x01D5
  81 #define L_AGON_REG              0x01D6
  82 #define L_AGOFF_REG             0x01D7
  83 /* Page 3 - Auto Exposure */
  84 #define AE_CTL_REG(n)           (0x0310 + (n))
  85 #define AE_CTL9_REG             0x032C
  86 #define AE_CTL10_REG            0x032D
  87 #define AE_YLVL_REG             0x031C
  88 #define AE_YTH_REG(n)           (0x031D + (n))
  89 #define AE_WGT_REG              0x0326
  90 #define EXP_TIMEH_REG           0x0333
  91 #define EXP_TIMEM_REG           0x0334
  92 #define EXP_TIMEL_REG           0x0335
  93 #define EXP_MMINH_REG           0x0336
  94 #define EXP_MMINL_REG           0x0337
  95 #define EXP_MMAXH_REG           0x0338
  96 #define EXP_MMAXM_REG           0x0339
  97 #define EXP_MMAXL_REG           0x033A
  98 /* Page 4 - Auto White Balance */
  99 #define AWB_CTL_REG(n)          (0x0410 + (n))
 100 #define AWB_ENABE               0x80
 101 #define AWB_WGHT_REG            0x0419
 102 #define BGAIN_PAR_REG(n)        (0x044F + (n))
 103 /* Manual white balance, when AWB_CTL2[0]=1 */
 104 #define MWB_RGAIN_REG           0x0466
 105 #define MWB_BGAIN_REG           0x0467
 106 
 107 /* The token to mark an array end */
 108 #define REG_TERM                0xFFFF
 109 
 110 struct noon010_format {
 111         u32 code;
 112         enum v4l2_colorspace colorspace;
 113         u16 ispctl1_reg;
 114 };
 115 
 116 struct noon010_frmsize {
 117         u16 width;
 118         u16 height;
 119         int vid_ctl1;
 120 };
 121 
 122 static const char * const noon010_supply_name[] = {
 123         "vdd_core", "vddio", "vdda"
 124 };
 125 
 126 #define NOON010_NUM_SUPPLIES ARRAY_SIZE(noon010_supply_name)
 127 
 128 struct noon010_info {
 129         struct v4l2_subdev sd;
 130         struct media_pad pad;
 131         struct v4l2_ctrl_handler hdl;
 132         struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES];
 133         u32 gpio_nreset;
 134         u32 gpio_nstby;
 135 
 136         /* Protects the struct members below */
 137         struct mutex lock;
 138 
 139         const struct noon010_format *curr_fmt;
 140         const struct noon010_frmsize *curr_win;
 141         unsigned int apply_new_cfg:1;
 142         unsigned int streaming:1;
 143         unsigned int hflip:1;
 144         unsigned int vflip:1;
 145         unsigned int power:1;
 146         u8 i2c_reg_page;
 147 };
 148 
 149 struct i2c_regval {
 150         u16 addr;
 151         u16 val;
 152 };
 153 
 154 /* Supported resolutions. */
 155 static const struct noon010_frmsize noon010_sizes[] = {
 156         {
 157                 .width          = 352,
 158                 .height         = 288,
 159                 .vid_ctl1       = 0,
 160         }, {
 161                 .width          = 176,
 162                 .height         = 144,
 163                 .vid_ctl1       = 0x10,
 164         }, {
 165                 .width          = 88,
 166                 .height         = 72,
 167                 .vid_ctl1       = 0x20,
 168         },
 169 };
 170 
 171 /* Supported pixel formats. */
 172 static const struct noon010_format noon010_formats[] = {
 173         {
 174                 .code           = MEDIA_BUS_FMT_YUYV8_2X8,
 175                 .colorspace     = V4L2_COLORSPACE_JPEG,
 176                 .ispctl1_reg    = 0x03,
 177         }, {
 178                 .code           = MEDIA_BUS_FMT_YVYU8_2X8,
 179                 .colorspace     = V4L2_COLORSPACE_JPEG,
 180                 .ispctl1_reg    = 0x02,
 181         }, {
 182                 .code           = MEDIA_BUS_FMT_VYUY8_2X8,
 183                 .colorspace     = V4L2_COLORSPACE_JPEG,
 184                 .ispctl1_reg    = 0,
 185         }, {
 186                 .code           = MEDIA_BUS_FMT_UYVY8_2X8,
 187                 .colorspace     = V4L2_COLORSPACE_JPEG,
 188                 .ispctl1_reg    = 0x01,
 189         }, {
 190                 .code           = MEDIA_BUS_FMT_RGB565_2X8_BE,
 191                 .colorspace     = V4L2_COLORSPACE_JPEG,
 192                 .ispctl1_reg    = 0x40,
 193         },
 194 };
 195 
 196 static const struct i2c_regval noon010_base_regs[] = {
 197         { WIN_COLL_REG,         0x06 }, { HBLANKL_REG,          0x7C },
 198         /* Color corection and saturation */
 199         { ISP_CTL_REG(0),       0x30 }, { ISP_CTL_REG(2),       0x30 },
 200         { YOFS_REG,             0x80 }, { DARK_YOFS_REG,        0x04 },
 201         { SAT_CTL_REG,          0x1F }, { BSAT_REG,             0x90 },
 202         { CMC_CTL_REG,          0x0F }, { CMC_OFSGH_REG,        0x3C },
 203         { CMC_OFSGL_REG,        0x2C }, { CMC_SIGN_REG,         0x3F },
 204         { CMC_COEF_REG(0),      0x79 }, { CMC_OFS_REG(0),       0x00 },
 205         { CMC_COEF_REG(1),      0x39 }, { CMC_OFS_REG(1),       0x00 },
 206         { CMC_COEF_REG(2),      0x00 }, { CMC_OFS_REG(2),       0x00 },
 207         { CMC_COEF_REG(3),      0x11 }, { CMC_OFS_REG(3),       0x8B },
 208         { CMC_COEF_REG(4),      0x65 }, { CMC_OFS_REG(4),       0x07 },
 209         { CMC_COEF_REG(5),      0x14 }, { CMC_OFS_REG(5),       0x04 },
 210         { CMC_COEF_REG(6),      0x01 }, { CMC_OFS_REG(6),       0x9C },
 211         { CMC_COEF_REG(7),      0x33 }, { CMC_OFS_REG(7),       0x89 },
 212         { CMC_COEF_REG(8),      0x74 }, { CMC_OFS_REG(8),       0x25 },
 213         /* Automatic white balance */
 214         { AWB_CTL_REG(0),       0x78 }, { AWB_CTL_REG(1),       0x2E },
 215         { AWB_CTL_REG(2),       0x20 }, { AWB_CTL_REG(3),       0x85 },
 216         /* Auto exposure */
 217         { AE_CTL_REG(0),        0xDC }, { AE_CTL_REG(1),        0x81 },
 218         { AE_CTL_REG(2),        0x30 }, { AE_CTL_REG(3),        0xA5 },
 219         { AE_CTL_REG(4),        0x40 }, { AE_CTL_REG(5),        0x51 },
 220         { AE_CTL_REG(6),        0x33 }, { AE_CTL_REG(7),        0x7E },
 221         { AE_CTL9_REG,          0x00 }, { AE_CTL10_REG,         0x02 },
 222         { AE_YLVL_REG,          0x44 }, { AE_YTH_REG(0),        0x34 },
 223         { AE_YTH_REG(1),        0x30 }, { AE_WGT_REG,           0xD5 },
 224         /* Lens shading compensation */
 225         { LENS_CTRL_REG,        0x01 }, { LENS_XCEN_REG,        0x80 },
 226         { LENS_YCEN_REG,        0x70 }, { LENS_RC_REG,          0x53 },
 227         { LENS_GC_REG,          0x40 }, { LENS_BC_REG,          0x3E },
 228         { REG_TERM,             0 },
 229 };
 230 
 231 static inline struct noon010_info *to_noon010(struct v4l2_subdev *sd)
 232 {
 233         return container_of(sd, struct noon010_info, sd);
 234 }
 235 
 236 static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
 237 {
 238         return &container_of(ctrl->handler, struct noon010_info, hdl)->sd;
 239 }
 240 
 241 static inline int set_i2c_page(struct noon010_info *info,
 242                                struct i2c_client *client, unsigned int reg)
 243 {
 244         u32 page = reg >> 8 & 0xFF;
 245         int ret = 0;
 246 
 247         if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) {
 248                 ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page);
 249                 if (!ret)
 250                         info->i2c_reg_page = page;
 251         }
 252         return ret;
 253 }
 254 
 255 static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr)
 256 {
 257         struct i2c_client *client = v4l2_get_subdevdata(sd);
 258         struct noon010_info *info = to_noon010(sd);
 259         int ret = set_i2c_page(info, client, reg_addr);
 260 
 261         if (ret)
 262                 return ret;
 263         return i2c_smbus_read_byte_data(client, reg_addr & 0xFF);
 264 }
 265 
 266 static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val)
 267 {
 268         struct i2c_client *client = v4l2_get_subdevdata(sd);
 269         struct noon010_info *info = to_noon010(sd);
 270         int ret = set_i2c_page(info, client, reg_addr);
 271 
 272         if (ret)
 273                 return ret;
 274         return i2c_smbus_write_byte_data(client, reg_addr & 0xFF, val);
 275 }
 276 
 277 static inline int noon010_bulk_write_reg(struct v4l2_subdev *sd,
 278                                          const struct i2c_regval *msg)
 279 {
 280         while (msg->addr != REG_TERM) {
 281                 int ret = cam_i2c_write(sd, msg->addr, msg->val);
 282 
 283                 if (ret)
 284                         return ret;
 285                 msg++;
 286         }
 287         return 0;
 288 }
 289 
 290 /* Device reset and sleep mode control */
 291 static int noon010_power_ctrl(struct v4l2_subdev *sd, bool reset, bool sleep)
 292 {
 293         struct noon010_info *info = to_noon010(sd);
 294         u8 reg = sleep ? 0xF1 : 0xF0;
 295         int ret = 0;
 296 
 297         if (reset) {
 298                 ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02);
 299                 udelay(20);
 300         }
 301         if (!ret) {
 302                 ret = cam_i2c_write(sd, POWER_CTRL_REG, reg);
 303                 if (reset && !ret)
 304                         info->i2c_reg_page = -1;
 305         }
 306         return ret;
 307 }
 308 
 309 /* Automatic white balance control */
 310 static int noon010_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
 311 {
 312         int ret;
 313 
 314         ret = cam_i2c_write(sd, AWB_CTL_REG(1), on ? 0x2E : 0x2F);
 315         if (!ret)
 316                 ret = cam_i2c_write(sd, AWB_CTL_REG(0), on ? 0xFB : 0x7B);
 317         return ret;
 318 }
 319 
 320 /* Called with struct noon010_info.lock mutex held */
 321 static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip)
 322 {
 323         struct noon010_info *info = to_noon010(sd);
 324         int reg, ret;
 325 
 326         reg = cam_i2c_read(sd, VDO_CTL_REG(1));
 327         if (reg < 0)
 328                 return reg;
 329 
 330         reg &= 0x7C;
 331         if (hflip)
 332                 reg |= 0x01;
 333         if (vflip)
 334                 reg |= 0x02;
 335 
 336         ret = cam_i2c_write(sd, VDO_CTL_REG(1), reg | 0x80);
 337         if (!ret) {
 338                 info->hflip = hflip;
 339                 info->vflip = vflip;
 340         }
 341         return ret;
 342 }
 343 
 344 /* Configure resolution and color format */
 345 static int noon010_set_params(struct v4l2_subdev *sd)
 346 {
 347         struct noon010_info *info = to_noon010(sd);
 348 
 349         int ret = cam_i2c_write(sd, VDO_CTL_REG(0),
 350                                 info->curr_win->vid_ctl1);
 351         if (ret)
 352                 return ret;
 353         return cam_i2c_write(sd, ISP_CTL_REG(0),
 354                              info->curr_fmt->ispctl1_reg);
 355 }
 356 
 357 /* Find nearest matching image pixel size. */
 358 static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf,
 359                                   const struct noon010_frmsize **size)
 360 {
 361         unsigned int min_err = ~0;
 362         int i = ARRAY_SIZE(noon010_sizes);
 363         const struct noon010_frmsize *fsize = &noon010_sizes[0],
 364                 *match = NULL;
 365 
 366         while (i--) {
 367                 int err = abs(fsize->width - mf->width)
 368                                 + abs(fsize->height - mf->height);
 369 
 370                 if (err < min_err) {
 371                         min_err = err;
 372                         match = fsize;
 373                 }
 374                 fsize++;
 375         }
 376         if (match) {
 377                 mf->width  = match->width;
 378                 mf->height = match->height;
 379                 if (size)
 380                         *size = match;
 381                 return 0;
 382         }
 383         return -EINVAL;
 384 }
 385 
 386 /* Called with info.lock mutex held */
 387 static int power_enable(struct noon010_info *info)
 388 {
 389         int ret;
 390 
 391         if (info->power) {
 392                 v4l2_info(&info->sd, "%s: sensor is already on\n", __func__);
 393                 return 0;
 394         }
 395 
 396         if (gpio_is_valid(info->gpio_nstby))
 397                 gpio_set_value(info->gpio_nstby, 0);
 398 
 399         if (gpio_is_valid(info->gpio_nreset))
 400                 gpio_set_value(info->gpio_nreset, 0);
 401 
 402         ret = regulator_bulk_enable(NOON010_NUM_SUPPLIES, info->supply);
 403         if (ret)
 404                 return ret;
 405 
 406         if (gpio_is_valid(info->gpio_nreset)) {
 407                 msleep(50);
 408                 gpio_set_value(info->gpio_nreset, 1);
 409         }
 410         if (gpio_is_valid(info->gpio_nstby)) {
 411                 udelay(1000);
 412                 gpio_set_value(info->gpio_nstby, 1);
 413         }
 414         if (gpio_is_valid(info->gpio_nreset)) {
 415                 udelay(1000);
 416                 gpio_set_value(info->gpio_nreset, 0);
 417                 msleep(100);
 418                 gpio_set_value(info->gpio_nreset, 1);
 419                 msleep(20);
 420         }
 421         info->power = 1;
 422 
 423         v4l2_dbg(1, debug, &info->sd,  "%s: sensor is on\n", __func__);
 424         return 0;
 425 }
 426 
 427 /* Called with info.lock mutex held */
 428 static int power_disable(struct noon010_info *info)
 429 {
 430         int ret;
 431 
 432         if (!info->power) {
 433                 v4l2_info(&info->sd, "%s: sensor is already off\n", __func__);
 434                 return 0;
 435         }
 436 
 437         ret = regulator_bulk_disable(NOON010_NUM_SUPPLIES, info->supply);
 438         if (ret)
 439                 return ret;
 440 
 441         if (gpio_is_valid(info->gpio_nstby))
 442                 gpio_set_value(info->gpio_nstby, 0);
 443 
 444         if (gpio_is_valid(info->gpio_nreset))
 445                 gpio_set_value(info->gpio_nreset, 0);
 446 
 447         info->power = 0;
 448 
 449         v4l2_dbg(1, debug, &info->sd,  "%s: sensor is off\n", __func__);
 450 
 451         return 0;
 452 }
 453 
 454 static int noon010_s_ctrl(struct v4l2_ctrl *ctrl)
 455 {
 456         struct v4l2_subdev *sd = to_sd(ctrl);
 457         struct noon010_info *info = to_noon010(sd);
 458         int ret = 0;
 459 
 460         v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
 461                  __func__, ctrl->id, ctrl->val);
 462 
 463         mutex_lock(&info->lock);
 464         /*
 465          * If the device is not powered up by the host driver do
 466          * not apply any controls to H/W at this time. Instead
 467          * the controls will be restored right after power-up.
 468          */
 469         if (!info->power)
 470                 goto unlock;
 471 
 472         switch (ctrl->id) {
 473         case V4L2_CID_AUTO_WHITE_BALANCE:
 474                 ret = noon010_enable_autowhitebalance(sd, ctrl->val);
 475                 break;
 476         case V4L2_CID_BLUE_BALANCE:
 477                 ret = cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val);
 478                 break;
 479         case V4L2_CID_RED_BALANCE:
 480                 ret =  cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val);
 481                 break;
 482         default:
 483                 ret = -EINVAL;
 484         }
 485 unlock:
 486         mutex_unlock(&info->lock);
 487         return ret;
 488 }
 489 
 490 static int noon010_enum_mbus_code(struct v4l2_subdev *sd,
 491                                   struct v4l2_subdev_pad_config *cfg,
 492                                   struct v4l2_subdev_mbus_code_enum *code)
 493 {
 494         if (code->index >= ARRAY_SIZE(noon010_formats))
 495                 return -EINVAL;
 496 
 497         code->code = noon010_formats[code->index].code;
 498         return 0;
 499 }
 500 
 501 static int noon010_get_fmt(struct v4l2_subdev *sd,
 502                            struct v4l2_subdev_pad_config *cfg,
 503                            struct v4l2_subdev_format *fmt)
 504 {
 505         struct noon010_info *info = to_noon010(sd);
 506         struct v4l2_mbus_framefmt *mf;
 507 
 508         if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 509                 if (cfg) {
 510                         mf = v4l2_subdev_get_try_format(sd, cfg, 0);
 511                         fmt->format = *mf;
 512                 }
 513                 return 0;
 514         }
 515         mf = &fmt->format;
 516 
 517         mutex_lock(&info->lock);
 518         mf->width = info->curr_win->width;
 519         mf->height = info->curr_win->height;
 520         mf->code = info->curr_fmt->code;
 521         mf->colorspace = info->curr_fmt->colorspace;
 522         mf->field = V4L2_FIELD_NONE;
 523 
 524         mutex_unlock(&info->lock);
 525         return 0;
 526 }
 527 
 528 /* Return nearest media bus frame format. */
 529 static const struct noon010_format *noon010_try_fmt(struct v4l2_subdev *sd,
 530                                             struct v4l2_mbus_framefmt *mf)
 531 {
 532         int i = ARRAY_SIZE(noon010_formats);
 533 
 534         while (--i)
 535                 if (mf->code == noon010_formats[i].code)
 536                         break;
 537         mf->code = noon010_formats[i].code;
 538 
 539         return &noon010_formats[i];
 540 }
 541 
 542 static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
 543                            struct v4l2_subdev_format *fmt)
 544 {
 545         struct noon010_info *info = to_noon010(sd);
 546         const struct noon010_frmsize *size = NULL;
 547         const struct noon010_format *nf;
 548         struct v4l2_mbus_framefmt *mf;
 549         int ret = 0;
 550 
 551         nf = noon010_try_fmt(sd, &fmt->format);
 552         noon010_try_frame_size(&fmt->format, &size);
 553         fmt->format.colorspace = V4L2_COLORSPACE_JPEG;
 554         fmt->format.field = V4L2_FIELD_NONE;
 555 
 556         if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 557                 if (cfg) {
 558                         mf = v4l2_subdev_get_try_format(sd, cfg, 0);
 559                         *mf = fmt->format;
 560                 }
 561                 return 0;
 562         }
 563         mutex_lock(&info->lock);
 564         if (!info->streaming) {
 565                 info->apply_new_cfg = 1;
 566                 info->curr_fmt = nf;
 567                 info->curr_win = size;
 568         } else {
 569                 ret = -EBUSY;
 570         }
 571         mutex_unlock(&info->lock);
 572         return ret;
 573 }
 574 
 575 /* Called with struct noon010_info.lock mutex held */
 576 static int noon010_base_config(struct v4l2_subdev *sd)
 577 {
 578         int ret = noon010_bulk_write_reg(sd, noon010_base_regs);
 579         if (!ret)
 580                 ret = noon010_set_params(sd);
 581         if (!ret)
 582                 ret = noon010_set_flip(sd, 1, 0);
 583 
 584         return ret;
 585 }
 586 
 587 static int noon010_s_power(struct v4l2_subdev *sd, int on)
 588 {
 589         struct noon010_info *info = to_noon010(sd);
 590         int ret;
 591 
 592         mutex_lock(&info->lock);
 593         if (on) {
 594                 ret = power_enable(info);
 595                 if (!ret)
 596                         ret = noon010_base_config(sd);
 597         } else {
 598                 noon010_power_ctrl(sd, false, true);
 599                 ret = power_disable(info);
 600         }
 601         mutex_unlock(&info->lock);
 602 
 603         /* Restore the controls state */
 604         if (!ret && on)
 605                 ret = v4l2_ctrl_handler_setup(&info->hdl);
 606 
 607         return ret;
 608 }
 609 
 610 static int noon010_s_stream(struct v4l2_subdev *sd, int on)
 611 {
 612         struct noon010_info *info = to_noon010(sd);
 613         int ret = 0;
 614 
 615         mutex_lock(&info->lock);
 616         if (!info->streaming != !on) {
 617                 ret = noon010_power_ctrl(sd, false, !on);
 618                 if (!ret)
 619                         info->streaming = on;
 620         }
 621         if (!ret && on && info->apply_new_cfg) {
 622                 ret = noon010_set_params(sd);
 623                 if (!ret)
 624                         info->apply_new_cfg = 0;
 625         }
 626         mutex_unlock(&info->lock);
 627         return ret;
 628 }
 629 
 630 static int noon010_log_status(struct v4l2_subdev *sd)
 631 {
 632         struct noon010_info *info = to_noon010(sd);
 633 
 634         v4l2_ctrl_handler_log_status(&info->hdl, sd->name);
 635         return 0;
 636 }
 637 
 638 static int noon010_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 639 {
 640         struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0);
 641 
 642         mf->width = noon010_sizes[0].width;
 643         mf->height = noon010_sizes[0].height;
 644         mf->code = noon010_formats[0].code;
 645         mf->colorspace = V4L2_COLORSPACE_JPEG;
 646         mf->field = V4L2_FIELD_NONE;
 647         return 0;
 648 }
 649 
 650 static const struct v4l2_subdev_internal_ops noon010_subdev_internal_ops = {
 651         .open = noon010_open,
 652 };
 653 
 654 static const struct v4l2_ctrl_ops noon010_ctrl_ops = {
 655         .s_ctrl = noon010_s_ctrl,
 656 };
 657 
 658 static const struct v4l2_subdev_core_ops noon010_core_ops = {
 659         .s_power        = noon010_s_power,
 660         .log_status     = noon010_log_status,
 661 };
 662 
 663 static const struct v4l2_subdev_pad_ops noon010_pad_ops = {
 664         .enum_mbus_code = noon010_enum_mbus_code,
 665         .get_fmt        = noon010_get_fmt,
 666         .set_fmt        = noon010_set_fmt,
 667 };
 668 
 669 static const struct v4l2_subdev_video_ops noon010_video_ops = {
 670         .s_stream       = noon010_s_stream,
 671 };
 672 
 673 static const struct v4l2_subdev_ops noon010_ops = {
 674         .core   = &noon010_core_ops,
 675         .pad    = &noon010_pad_ops,
 676         .video  = &noon010_video_ops,
 677 };
 678 
 679 /* Return 0 if NOON010PC30L sensor type was detected or -ENODEV otherwise. */
 680 static int noon010_detect(struct i2c_client *client, struct noon010_info *info)
 681 {
 682         int ret;
 683 
 684         ret = power_enable(info);
 685         if (ret)
 686                 return ret;
 687 
 688         ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG);
 689         if (ret < 0)
 690                 dev_err(&client->dev, "I2C read failed: 0x%X\n", ret);
 691 
 692         power_disable(info);
 693 
 694         return ret == NOON010PC30_ID ? 0 : -ENODEV;
 695 }
 696 
 697 static int noon010_probe(struct i2c_client *client,
 698                          const struct i2c_device_id *id)
 699 {
 700         struct noon010_info *info;
 701         struct v4l2_subdev *sd;
 702         const struct noon010pc30_platform_data *pdata
 703                 = client->dev.platform_data;
 704         int ret;
 705         int i;
 706 
 707         if (!pdata) {
 708                 dev_err(&client->dev, "No platform data!\n");
 709                 return -EIO;
 710         }
 711 
 712         info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
 713         if (!info)
 714                 return -ENOMEM;
 715 
 716         mutex_init(&info->lock);
 717         sd = &info->sd;
 718         v4l2_i2c_subdev_init(sd, client, &noon010_ops);
 719         /* Static name; NEVER use in new drivers! */
 720         strscpy(sd->name, MODULE_NAME, sizeof(sd->name));
 721 
 722         sd->internal_ops = &noon010_subdev_internal_ops;
 723         sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 724 
 725         v4l2_ctrl_handler_init(&info->hdl, 3);
 726 
 727         v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
 728                           V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
 729         v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
 730                           V4L2_CID_RED_BALANCE, 0, 127, 1, 64);
 731         v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
 732                           V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64);
 733 
 734         sd->ctrl_handler = &info->hdl;
 735 
 736         ret = info->hdl.error;
 737         if (ret)
 738                 goto np_err;
 739 
 740         info->i2c_reg_page      = -1;
 741         info->gpio_nreset       = -EINVAL;
 742         info->gpio_nstby        = -EINVAL;
 743         info->curr_fmt          = &noon010_formats[0];
 744         info->curr_win          = &noon010_sizes[0];
 745 
 746         if (gpio_is_valid(pdata->gpio_nreset)) {
 747                 ret = devm_gpio_request_one(&client->dev, pdata->gpio_nreset,
 748                                             GPIOF_OUT_INIT_LOW,
 749                                             "NOON010PC30 NRST");
 750                 if (ret) {
 751                         dev_err(&client->dev, "GPIO request error: %d\n", ret);
 752                         goto np_err;
 753                 }
 754                 info->gpio_nreset = pdata->gpio_nreset;
 755                 gpio_export(info->gpio_nreset, 0);
 756         }
 757 
 758         if (gpio_is_valid(pdata->gpio_nstby)) {
 759                 ret = devm_gpio_request_one(&client->dev, pdata->gpio_nstby,
 760                                             GPIOF_OUT_INIT_LOW,
 761                                             "NOON010PC30 NSTBY");
 762                 if (ret) {
 763                         dev_err(&client->dev, "GPIO request error: %d\n", ret);
 764                         goto np_err;
 765                 }
 766                 info->gpio_nstby = pdata->gpio_nstby;
 767                 gpio_export(info->gpio_nstby, 0);
 768         }
 769 
 770         for (i = 0; i < NOON010_NUM_SUPPLIES; i++)
 771                 info->supply[i].supply = noon010_supply_name[i];
 772 
 773         ret = devm_regulator_bulk_get(&client->dev, NOON010_NUM_SUPPLIES,
 774                                  info->supply);
 775         if (ret)
 776                 goto np_err;
 777 
 778         info->pad.flags = MEDIA_PAD_FL_SOURCE;
 779         sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
 780         ret = media_entity_pads_init(&sd->entity, 1, &info->pad);
 781         if (ret < 0)
 782                 goto np_err;
 783 
 784         ret = noon010_detect(client, info);
 785         if (!ret)
 786                 return 0;
 787 
 788 np_err:
 789         v4l2_ctrl_handler_free(&info->hdl);
 790         v4l2_device_unregister_subdev(sd);
 791         return ret;
 792 }
 793 
 794 static int noon010_remove(struct i2c_client *client)
 795 {
 796         struct v4l2_subdev *sd = i2c_get_clientdata(client);
 797         struct noon010_info *info = to_noon010(sd);
 798 
 799         v4l2_device_unregister_subdev(sd);
 800         v4l2_ctrl_handler_free(&info->hdl);
 801         media_entity_cleanup(&sd->entity);
 802 
 803         return 0;
 804 }
 805 
 806 static const struct i2c_device_id noon010_id[] = {
 807         { MODULE_NAME, 0 },
 808         { },
 809 };
 810 MODULE_DEVICE_TABLE(i2c, noon010_id);
 811 
 812 
 813 static struct i2c_driver noon010_i2c_driver = {
 814         .driver = {
 815                 .name = MODULE_NAME
 816         },
 817         .probe          = noon010_probe,
 818         .remove         = noon010_remove,
 819         .id_table       = noon010_id,
 820 };
 821 
 822 module_i2c_driver(noon010_i2c_driver);
 823 
 824 MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver");
 825 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
 826 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */