linux/drivers/media/video/tcm825x.c
<<
>>
Prefs
   1/*
   2 * drivers/media/video/tcm825x.c
   3 *
   4 * TCM825X camera sensor driver.
   5 *
   6 * Copyright (C) 2007 Nokia Corporation.
   7 *
   8 * Contact: Sakari Ailus <sakari.ailus@nokia.com>
   9 *
  10 * Based on code from David Cohen <david.cohen@indt.org.br>
  11 *
  12 * This driver was based on ov9640 sensor driver from MontaVista
  13 *
  14 * This program is free software; you can redistribute it and/or
  15 * modify it under the terms of the GNU General Public License
  16 * version 2 as published by the Free Software Foundation.
  17 *
  18 * This program is distributed in the hope that it will be useful, but
  19 * WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  21 * General Public License for more details.
  22 *
  23 * You should have received a copy of the GNU General Public License
  24 * along with this program; if not, write to the Free Software
  25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  26 * 02110-1301 USA
  27 */
  28
  29#include <linux/i2c.h>
  30#include <media/v4l2-int-device.h>
  31
  32#include "tcm825x.h"
  33
  34/*
  35 * The sensor has two fps modes: the lower one just gives half the fps
  36 * at the same xclk than the high one.
  37 */
  38#define MAX_FPS 30
  39#define MIN_FPS 8
  40#define MAX_HALF_FPS (MAX_FPS / 2)
  41#define HIGH_FPS_MODE_LOWER_LIMIT 14
  42#define DEFAULT_FPS MAX_HALF_FPS
  43
  44struct tcm825x_sensor {
  45        const struct tcm825x_platform_data *platform_data;
  46        struct v4l2_int_device *v4l2_int_device;
  47        struct i2c_client *i2c_client;
  48        struct v4l2_pix_format pix;
  49        struct v4l2_fract timeperframe;
  50};
  51
  52/* list of image formats supported by TCM825X sensor */
  53static const struct v4l2_fmtdesc tcm825x_formats[] = {
  54        {
  55                .description = "YUYV (YUV 4:2:2), packed",
  56                .pixelformat = V4L2_PIX_FMT_UYVY,
  57        }, {
  58                /* Note:  V4L2 defines RGB565 as:
  59                 *
  60                 *      Byte 0                    Byte 1
  61                 *      g2 g1 g0 r4 r3 r2 r1 r0   b4 b3 b2 b1 b0 g5 g4 g3
  62                 *
  63                 * We interpret RGB565 as:
  64                 *
  65                 *      Byte 0                    Byte 1
  66                 *      g2 g1 g0 b4 b3 b2 b1 b0   r4 r3 r2 r1 r0 g5 g4 g3
  67                 */
  68                .description = "RGB565, le",
  69                .pixelformat = V4L2_PIX_FMT_RGB565,
  70        },
  71};
  72
  73#define TCM825X_NUM_CAPTURE_FORMATS     ARRAY_SIZE(tcm825x_formats)
  74
  75/*
  76 * TCM825X register configuration for all combinations of pixel format and
  77 * image size
  78 */
  79static const struct tcm825x_reg subqcif =       { 0x20, TCM825X_PICSIZ };
  80static const struct tcm825x_reg qcif    =       { 0x18, TCM825X_PICSIZ };
  81static const struct tcm825x_reg cif     =       { 0x14, TCM825X_PICSIZ };
  82static const struct tcm825x_reg qqvga   =       { 0x0c, TCM825X_PICSIZ };
  83static const struct tcm825x_reg qvga    =       { 0x04, TCM825X_PICSIZ };
  84static const struct tcm825x_reg vga     =       { 0x00, TCM825X_PICSIZ };
  85
  86static const struct tcm825x_reg yuv422  =       { 0x00, TCM825X_PICFMT };
  87static const struct tcm825x_reg rgb565  =       { 0x02, TCM825X_PICFMT };
  88
  89/* Our own specific controls */
  90#define V4L2_CID_ALC                            V4L2_CID_PRIVATE_BASE
  91#define V4L2_CID_H_EDGE_EN                      V4L2_CID_PRIVATE_BASE + 1
  92#define V4L2_CID_V_EDGE_EN                      V4L2_CID_PRIVATE_BASE + 2
  93#define V4L2_CID_LENS                           V4L2_CID_PRIVATE_BASE + 3
  94#define V4L2_CID_MAX_EXPOSURE_TIME              V4L2_CID_PRIVATE_BASE + 4
  95#define V4L2_CID_LAST_PRIV                      V4L2_CID_MAX_EXPOSURE_TIME
  96
  97/*  Video controls  */
  98static struct vcontrol {
  99        struct v4l2_queryctrl qc;
 100        u16 reg;
 101        u16 start_bit;
 102} video_control[] = {
 103        {
 104                {
 105                        .id = V4L2_CID_GAIN,
 106                        .type = V4L2_CTRL_TYPE_INTEGER,
 107                        .name = "Gain",
 108                        .minimum = 0,
 109                        .maximum = 63,
 110                        .step = 1,
 111                },
 112                .reg = TCM825X_AG,
 113                .start_bit = 0,
 114        },
 115        {
 116                {
 117                        .id = V4L2_CID_RED_BALANCE,
 118                        .type = V4L2_CTRL_TYPE_INTEGER,
 119                        .name = "Red Balance",
 120                        .minimum = 0,
 121                        .maximum = 255,
 122                        .step = 1,
 123                },
 124                .reg = TCM825X_MRG,
 125                .start_bit = 0,
 126        },
 127        {
 128                {
 129                        .id = V4L2_CID_BLUE_BALANCE,
 130                        .type = V4L2_CTRL_TYPE_INTEGER,
 131                        .name = "Blue Balance",
 132                        .minimum = 0,
 133                        .maximum = 255,
 134                        .step = 1,
 135                },
 136                .reg = TCM825X_MBG,
 137                .start_bit = 0,
 138        },
 139        {
 140                {
 141                        .id = V4L2_CID_AUTO_WHITE_BALANCE,
 142                        .type = V4L2_CTRL_TYPE_BOOLEAN,
 143                        .name = "Auto White Balance",
 144                        .minimum = 0,
 145                        .maximum = 1,
 146                        .step = 0,
 147                },
 148                .reg = TCM825X_AWBSW,
 149                .start_bit = 7,
 150        },
 151        {
 152                {
 153                        .id = V4L2_CID_EXPOSURE,
 154                        .type = V4L2_CTRL_TYPE_INTEGER,
 155                        .name = "Exposure Time",
 156                        .minimum = 0,
 157                        .maximum = 0x1fff,
 158                        .step = 1,
 159                },
 160                .reg = TCM825X_ESRSPD_U,
 161                .start_bit = 0,
 162        },
 163        {
 164                {
 165                        .id = V4L2_CID_HFLIP,
 166                        .type = V4L2_CTRL_TYPE_BOOLEAN,
 167                        .name = "Mirror Image",
 168                        .minimum = 0,
 169                        .maximum = 1,
 170                        .step = 0,
 171                },
 172                .reg = TCM825X_H_INV,
 173                .start_bit = 6,
 174        },
 175        {
 176                {
 177                        .id = V4L2_CID_VFLIP,
 178                        .type = V4L2_CTRL_TYPE_BOOLEAN,
 179                        .name = "Vertical Flip",
 180                        .minimum = 0,
 181                        .maximum = 1,
 182                        .step = 0,
 183                },
 184                .reg = TCM825X_V_INV,
 185                .start_bit = 7,
 186        },
 187        /* Private controls */
 188        {
 189                {
 190                        .id = V4L2_CID_ALC,
 191                        .type = V4L2_CTRL_TYPE_BOOLEAN,
 192                        .name = "Auto Luminance Control",
 193                        .minimum = 0,
 194                        .maximum = 1,
 195                        .step = 0,
 196                },
 197                .reg = TCM825X_ALCSW,
 198                .start_bit = 7,
 199        },
 200        {
 201                {
 202                        .id = V4L2_CID_H_EDGE_EN,
 203                        .type = V4L2_CTRL_TYPE_INTEGER,
 204                        .name = "Horizontal Edge Enhancement",
 205                        .minimum = 0,
 206                        .maximum = 0xff,
 207                        .step = 1,
 208                },
 209                .reg = TCM825X_HDTG,
 210                .start_bit = 0,
 211        },
 212        {
 213                {
 214                        .id = V4L2_CID_V_EDGE_EN,
 215                        .type = V4L2_CTRL_TYPE_INTEGER,
 216                        .name = "Vertical Edge Enhancement",
 217                        .minimum = 0,
 218                        .maximum = 0xff,
 219                        .step = 1,
 220                },
 221                .reg = TCM825X_VDTG,
 222                .start_bit = 0,
 223        },
 224        {
 225                {
 226                        .id = V4L2_CID_LENS,
 227                        .type = V4L2_CTRL_TYPE_INTEGER,
 228                        .name = "Lens Shading Compensation",
 229                        .minimum = 0,
 230                        .maximum = 0x3f,
 231                        .step = 1,
 232                },
 233                .reg = TCM825X_LENS,
 234                .start_bit = 0,
 235        },
 236        {
 237                {
 238                        .id = V4L2_CID_MAX_EXPOSURE_TIME,
 239                        .type = V4L2_CTRL_TYPE_INTEGER,
 240                        .name = "Maximum Exposure Time",
 241                        .minimum = 0,
 242                        .maximum = 0x3,
 243                        .step = 1,
 244                },
 245                .reg = TCM825X_ESRLIM,
 246                .start_bit = 5,
 247        },
 248};
 249
 250
 251static const struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
 252{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
 253
 254static const struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
 255{ &yuv422, &rgb565 };
 256
 257/*
 258 * Read a value from a register in an TCM825X sensor device.  The value is
 259 * returned in 'val'.
 260 * Returns zero if successful, or non-zero otherwise.
 261 */
 262static int tcm825x_read_reg(struct i2c_client *client, int reg)
 263{
 264        int err;
 265        struct i2c_msg msg[2];
 266        u8 reg_buf, data_buf = 0;
 267
 268        if (!client->adapter)
 269                return -ENODEV;
 270
 271        msg[0].addr = client->addr;
 272        msg[0].flags = 0;
 273        msg[0].len = 1;
 274        msg[0].buf = &reg_buf;
 275        msg[1].addr = client->addr;
 276        msg[1].flags = I2C_M_RD;
 277        msg[1].len = 1;
 278        msg[1].buf = &data_buf;
 279
 280        reg_buf = reg;
 281
 282        err = i2c_transfer(client->adapter, msg, 2);
 283        if (err < 0)
 284                return err;
 285        return data_buf;
 286}
 287
 288/*
 289 * Write a value to a register in an TCM825X sensor device.
 290 * Returns zero if successful, or non-zero otherwise.
 291 */
 292static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val)
 293{
 294        int err;
 295        struct i2c_msg msg[1];
 296        unsigned char data[2];
 297
 298        if (!client->adapter)
 299                return -ENODEV;
 300
 301        msg->addr = client->addr;
 302        msg->flags = 0;
 303        msg->len = 2;
 304        msg->buf = data;
 305        data[0] = reg;
 306        data[1] = val;
 307        err = i2c_transfer(client->adapter, msg, 1);
 308        if (err >= 0)
 309                return 0;
 310        return err;
 311}
 312
 313static int __tcm825x_write_reg_mask(struct i2c_client *client,
 314                                    u8 reg, u8 val, u8 mask)
 315{
 316        int rc;
 317
 318        /* need to do read - modify - write */
 319        rc = tcm825x_read_reg(client, reg);
 320        if (rc < 0)
 321                return rc;
 322
 323        rc &= (~mask);  /* Clear the masked bits */
 324        val &= mask;    /* Enforce mask on value */
 325        val |= rc;
 326
 327        /* write the new value to the register */
 328        rc = tcm825x_write_reg(client, reg, val);
 329        if (rc)
 330                return rc;
 331
 332        return 0;
 333}
 334
 335#define tcm825x_write_reg_mask(client, regmask, val)                    \
 336        __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val,  \
 337                                 TCM825X_MASK((regmask)))
 338
 339
 340/*
 341 * Initialize a list of TCM825X registers.
 342 * The list of registers is terminated by the pair of values
 343 * { TCM825X_REG_TERM, TCM825X_VAL_TERM }.
 344 * Returns zero if successful, or non-zero otherwise.
 345 */
 346static int tcm825x_write_default_regs(struct i2c_client *client,
 347                                      const struct tcm825x_reg *reglist)
 348{
 349        int err;
 350        const struct tcm825x_reg *next = reglist;
 351
 352        while (!((next->reg == TCM825X_REG_TERM)
 353                 && (next->val == TCM825X_VAL_TERM))) {
 354                err = tcm825x_write_reg(client, next->reg, next->val);
 355                if (err) {
 356                        dev_err(&client->dev, "register writing failed\n");
 357                        return err;
 358                }
 359                next++;
 360        }
 361
 362        return 0;
 363}
 364
 365static struct vcontrol *find_vctrl(int id)
 366{
 367        int i;
 368
 369        if (id < V4L2_CID_BASE)
 370                return NULL;
 371
 372        for (i = 0; i < ARRAY_SIZE(video_control); i++)
 373                if (video_control[i].qc.id == id)
 374                        return &video_control[i];
 375
 376        return NULL;
 377}
 378
 379/*
 380 * Find the best match for a requested image capture size.  The best match
 381 * is chosen as the nearest match that has the same number or fewer pixels
 382 * as the requested size, or the smallest image size if the requested size
 383 * has fewer pixels than the smallest image.
 384 */
 385static enum image_size tcm825x_find_size(struct v4l2_int_device *s,
 386                                         unsigned int width,
 387                                         unsigned int height)
 388{
 389        enum image_size isize;
 390        unsigned long pixels = width * height;
 391        struct tcm825x_sensor *sensor = s->priv;
 392
 393        for (isize = subQCIF; isize < VGA; isize++) {
 394                if (tcm825x_sizes[isize + 1].height
 395                    * tcm825x_sizes[isize + 1].width > pixels) {
 396                        dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize);
 397
 398                        return isize;
 399                }
 400        }
 401
 402        dev_dbg(&sensor->i2c_client->dev, "format default VGA\n");
 403
 404        return VGA;
 405}
 406
 407/*
 408 * Configure the TCM825X for current image size, pixel format, and
 409 * frame period. fper is the frame period (in seconds) expressed as a
 410 * fraction. Returns zero if successful, or non-zero otherwise. The
 411 * actual frame period is returned in fper.
 412 */
 413static int tcm825x_configure(struct v4l2_int_device *s)
 414{
 415        struct tcm825x_sensor *sensor = s->priv;
 416        struct v4l2_pix_format *pix = &sensor->pix;
 417        enum image_size isize = tcm825x_find_size(s, pix->width, pix->height);
 418        struct v4l2_fract *fper = &sensor->timeperframe;
 419        enum pixel_format pfmt;
 420        int err;
 421        u32 tgt_fps;
 422        u8 val;
 423
 424        /* common register initialization */
 425        err = tcm825x_write_default_regs(
 426                sensor->i2c_client, sensor->platform_data->default_regs());
 427        if (err)
 428                return err;
 429
 430        /* configure image size */
 431        val = tcm825x_siz_reg[isize]->val;
 432        dev_dbg(&sensor->i2c_client->dev,
 433                "configuring image size %d\n", isize);
 434        err = tcm825x_write_reg_mask(sensor->i2c_client,
 435                                     tcm825x_siz_reg[isize]->reg, val);
 436        if (err)
 437                return err;
 438
 439        /* configure pixel format */
 440        switch (pix->pixelformat) {
 441        default:
 442        case V4L2_PIX_FMT_RGB565:
 443                pfmt = RGB565;
 444                break;
 445        case V4L2_PIX_FMT_UYVY:
 446                pfmt = YUV422;
 447                break;
 448        }
 449
 450        dev_dbg(&sensor->i2c_client->dev,
 451                "configuring pixel format %d\n", pfmt);
 452        val = tcm825x_fmt_reg[pfmt]->val;
 453
 454        err = tcm825x_write_reg_mask(sensor->i2c_client,
 455                                     tcm825x_fmt_reg[pfmt]->reg, val);
 456        if (err)
 457                return err;
 458
 459        /*
 460         * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be
 461         * set. Frame rate will be halved from the normal.
 462         */
 463        tgt_fps = fper->denominator / fper->numerator;
 464        if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) {
 465                val = tcm825x_read_reg(sensor->i2c_client, 0x02);
 466                val |= 0x80;
 467                tcm825x_write_reg(sensor->i2c_client, 0x02, val);
 468        }
 469
 470        return 0;
 471}
 472
 473static int ioctl_queryctrl(struct v4l2_int_device *s,
 474                                struct v4l2_queryctrl *qc)
 475{
 476        struct vcontrol *control;
 477
 478        control = find_vctrl(qc->id);
 479
 480        if (control == NULL)
 481                return -EINVAL;
 482
 483        *qc = control->qc;
 484
 485        return 0;
 486}
 487
 488static int ioctl_g_ctrl(struct v4l2_int_device *s,
 489                             struct v4l2_control *vc)
 490{
 491        struct tcm825x_sensor *sensor = s->priv;
 492        struct i2c_client *client = sensor->i2c_client;
 493        int val, r;
 494        struct vcontrol *lvc;
 495
 496        /* exposure time is special, spread accross 2 registers */
 497        if (vc->id == V4L2_CID_EXPOSURE) {
 498                int val_lower, val_upper;
 499
 500                val_upper = tcm825x_read_reg(client,
 501                                             TCM825X_ADDR(TCM825X_ESRSPD_U));
 502                if (val_upper < 0)
 503                        return val_upper;
 504                val_lower = tcm825x_read_reg(client,
 505                                             TCM825X_ADDR(TCM825X_ESRSPD_L));
 506                if (val_lower < 0)
 507                        return val_lower;
 508
 509                vc->value = ((val_upper & 0x1f) << 8) | (val_lower);
 510                return 0;
 511        }
 512
 513        lvc = find_vctrl(vc->id);
 514        if (lvc == NULL)
 515                return -EINVAL;
 516
 517        r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg));
 518        if (r < 0)
 519                return r;
 520        val = r & TCM825X_MASK(lvc->reg);
 521        val >>= lvc->start_bit;
 522
 523        if (val < 0)
 524                return val;
 525
 526        if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
 527                val ^= sensor->platform_data->is_upside_down();
 528
 529        vc->value = val;
 530        return 0;
 531}
 532
 533static int ioctl_s_ctrl(struct v4l2_int_device *s,
 534                             struct v4l2_control *vc)
 535{
 536        struct tcm825x_sensor *sensor = s->priv;
 537        struct i2c_client *client = sensor->i2c_client;
 538        struct vcontrol *lvc;
 539        int val = vc->value;
 540
 541        /* exposure time is special, spread accross 2 registers */
 542        if (vc->id == V4L2_CID_EXPOSURE) {
 543                int val_lower, val_upper;
 544                val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L);
 545                val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U);
 546
 547                if (tcm825x_write_reg_mask(client,
 548                                           TCM825X_ESRSPD_U, val_upper))
 549                        return -EIO;
 550
 551                if (tcm825x_write_reg_mask(client,
 552                                           TCM825X_ESRSPD_L, val_lower))
 553                        return -EIO;
 554
 555                return 0;
 556        }
 557
 558        lvc = find_vctrl(vc->id);
 559        if (lvc == NULL)
 560                return -EINVAL;
 561
 562        if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
 563                val ^= sensor->platform_data->is_upside_down();
 564
 565        val = val << lvc->start_bit;
 566        if (tcm825x_write_reg_mask(client, lvc->reg, val))
 567                return -EIO;
 568
 569        return 0;
 570}
 571
 572static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
 573                                   struct v4l2_fmtdesc *fmt)
 574{
 575        int index = fmt->index;
 576
 577        switch (fmt->type) {
 578        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 579                if (index >= TCM825X_NUM_CAPTURE_FORMATS)
 580                        return -EINVAL;
 581                break;
 582
 583        default:
 584                return -EINVAL;
 585        }
 586
 587        fmt->flags = tcm825x_formats[index].flags;
 588        strlcpy(fmt->description, tcm825x_formats[index].description,
 589                sizeof(fmt->description));
 590        fmt->pixelformat = tcm825x_formats[index].pixelformat;
 591
 592        return 0;
 593}
 594
 595static int ioctl_try_fmt_cap(struct v4l2_int_device *s,
 596                             struct v4l2_format *f)
 597{
 598        struct tcm825x_sensor *sensor = s->priv;
 599        enum image_size isize;
 600        int ifmt;
 601        struct v4l2_pix_format *pix = &f->fmt.pix;
 602
 603        isize = tcm825x_find_size(s, pix->width, pix->height);
 604        dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n",
 605                isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS);
 606
 607        pix->width = tcm825x_sizes[isize].width;
 608        pix->height = tcm825x_sizes[isize].height;
 609
 610        for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++)
 611                if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat)
 612                        break;
 613
 614        if (ifmt == TCM825X_NUM_CAPTURE_FORMATS)
 615                ifmt = 0;       /* Default = YUV 4:2:2 */
 616
 617        pix->pixelformat = tcm825x_formats[ifmt].pixelformat;
 618        pix->field = V4L2_FIELD_NONE;
 619        pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL;
 620        pix->sizeimage = pix->bytesperline * pix->height;
 621        pix->priv = 0;
 622        dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n",
 623                pix->pixelformat);
 624
 625        switch (pix->pixelformat) {
 626        case V4L2_PIX_FMT_UYVY:
 627        default:
 628                pix->colorspace = V4L2_COLORSPACE_JPEG;
 629                break;
 630        case V4L2_PIX_FMT_RGB565:
 631                pix->colorspace = V4L2_COLORSPACE_SRGB;
 632                break;
 633        }
 634
 635        return 0;
 636}
 637
 638static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
 639                                struct v4l2_format *f)
 640{
 641        struct tcm825x_sensor *sensor = s->priv;
 642        struct v4l2_pix_format *pix = &f->fmt.pix;
 643        int rval;
 644
 645        rval = ioctl_try_fmt_cap(s, f);
 646        if (rval)
 647                return rval;
 648
 649        rval = tcm825x_configure(s);
 650
 651        sensor->pix = *pix;
 652
 653        return rval;
 654}
 655
 656static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
 657                                struct v4l2_format *f)
 658{
 659        struct tcm825x_sensor *sensor = s->priv;
 660
 661        f->fmt.pix = sensor->pix;
 662
 663        return 0;
 664}
 665
 666static int ioctl_g_parm(struct v4l2_int_device *s,
 667                             struct v4l2_streamparm *a)
 668{
 669        struct tcm825x_sensor *sensor = s->priv;
 670        struct v4l2_captureparm *cparm = &a->parm.capture;
 671
 672        if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 673                return -EINVAL;
 674
 675        memset(a, 0, sizeof(*a));
 676        a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 677
 678        cparm->capability = V4L2_CAP_TIMEPERFRAME;
 679        cparm->timeperframe = sensor->timeperframe;
 680
 681        return 0;
 682}
 683
 684static int ioctl_s_parm(struct v4l2_int_device *s,
 685                             struct v4l2_streamparm *a)
 686{
 687        struct tcm825x_sensor *sensor = s->priv;
 688        struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
 689        u32 tgt_fps;    /* target frames per secound */
 690        int rval;
 691
 692        if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 693                return -EINVAL;
 694
 695        if ((timeperframe->numerator == 0)
 696            || (timeperframe->denominator == 0)) {
 697                timeperframe->denominator = DEFAULT_FPS;
 698                timeperframe->numerator = 1;
 699        }
 700
 701        tgt_fps = timeperframe->denominator / timeperframe->numerator;
 702
 703        if (tgt_fps > MAX_FPS) {
 704                timeperframe->denominator = MAX_FPS;
 705                timeperframe->numerator = 1;
 706        } else if (tgt_fps < MIN_FPS) {
 707                timeperframe->denominator = MIN_FPS;
 708                timeperframe->numerator = 1;
 709        }
 710
 711        sensor->timeperframe = *timeperframe;
 712
 713        rval = tcm825x_configure(s);
 714
 715        return rval;
 716}
 717
 718static int ioctl_s_power(struct v4l2_int_device *s, int on)
 719{
 720        struct tcm825x_sensor *sensor = s->priv;
 721
 722        return sensor->platform_data->power_set(on);
 723}
 724
 725/*
 726 * Given the image capture format in pix, the nominal frame period in
 727 * timeperframe, calculate the required xclk frequency.
 728 *
 729 * TCM825X input frequency characteristics are:
 730 *     Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz
 731 */
 732
 733static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
 734{
 735        struct tcm825x_sensor *sensor = s->priv;
 736        struct v4l2_fract *timeperframe = &sensor->timeperframe;
 737        u32 tgt_xclk;   /* target xclk */
 738        u32 tgt_fps;    /* target frames per secound */
 739        int rval;
 740
 741        rval = sensor->platform_data->ifparm(p);
 742        if (rval)
 743                return rval;
 744
 745        tgt_fps = timeperframe->denominator / timeperframe->numerator;
 746
 747        tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ?
 748                (2457 * tgt_fps) / MAX_HALF_FPS :
 749                (2457 * tgt_fps) / MAX_FPS;
 750        tgt_xclk *= 10000;
 751
 752        tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX);
 753        tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN);
 754
 755        p->u.bt656.clock_curr = tgt_xclk;
 756
 757        return 0;
 758}
 759
 760static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf)
 761{
 762        struct tcm825x_sensor *sensor = s->priv;
 763
 764        return sensor->platform_data->needs_reset(s, buf, &sensor->pix);
 765}
 766
 767static int ioctl_reset(struct v4l2_int_device *s)
 768{
 769        return -EBUSY;
 770}
 771
 772static int ioctl_init(struct v4l2_int_device *s)
 773{
 774        return tcm825x_configure(s);
 775}
 776
 777static int ioctl_dev_exit(struct v4l2_int_device *s)
 778{
 779        return 0;
 780}
 781
 782static int ioctl_dev_init(struct v4l2_int_device *s)
 783{
 784        struct tcm825x_sensor *sensor = s->priv;
 785        int r;
 786
 787        r = tcm825x_read_reg(sensor->i2c_client, 0x01);
 788        if (r < 0)
 789                return r;
 790        if (r == 0) {
 791                dev_err(&sensor->i2c_client->dev, "device not detected\n");
 792                return -EIO;
 793        }
 794        return 0;
 795}
 796
 797static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = {
 798        { vidioc_int_dev_init_num,
 799          (v4l2_int_ioctl_func *)ioctl_dev_init },
 800        { vidioc_int_dev_exit_num,
 801          (v4l2_int_ioctl_func *)ioctl_dev_exit },
 802        { vidioc_int_s_power_num,
 803          (v4l2_int_ioctl_func *)ioctl_s_power },
 804        { vidioc_int_g_ifparm_num,
 805          (v4l2_int_ioctl_func *)ioctl_g_ifparm },
 806        { vidioc_int_g_needs_reset_num,
 807          (v4l2_int_ioctl_func *)ioctl_g_needs_reset },
 808        { vidioc_int_reset_num,
 809          (v4l2_int_ioctl_func *)ioctl_reset },
 810        { vidioc_int_init_num,
 811          (v4l2_int_ioctl_func *)ioctl_init },
 812        { vidioc_int_enum_fmt_cap_num,
 813          (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
 814        { vidioc_int_try_fmt_cap_num,
 815          (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },
 816        { vidioc_int_g_fmt_cap_num,
 817          (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
 818        { vidioc_int_s_fmt_cap_num,
 819          (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },
 820        { vidioc_int_g_parm_num,
 821          (v4l2_int_ioctl_func *)ioctl_g_parm },
 822        { vidioc_int_s_parm_num,
 823          (v4l2_int_ioctl_func *)ioctl_s_parm },
 824        { vidioc_int_queryctrl_num,
 825          (v4l2_int_ioctl_func *)ioctl_queryctrl },
 826        { vidioc_int_g_ctrl_num,
 827          (v4l2_int_ioctl_func *)ioctl_g_ctrl },
 828        { vidioc_int_s_ctrl_num,
 829          (v4l2_int_ioctl_func *)ioctl_s_ctrl },
 830};
 831
 832static struct v4l2_int_slave tcm825x_slave = {
 833        .ioctls = tcm825x_ioctl_desc,
 834        .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc),
 835};
 836
 837static struct tcm825x_sensor tcm825x;
 838
 839static struct v4l2_int_device tcm825x_int_device = {
 840        .module = THIS_MODULE,
 841        .name = TCM825X_NAME,
 842        .priv = &tcm825x,
 843        .type = v4l2_int_type_slave,
 844        .u = {
 845                .slave = &tcm825x_slave,
 846        },
 847};
 848
 849static int tcm825x_probe(struct i2c_client *client,
 850                         const struct i2c_device_id *did)
 851{
 852        struct tcm825x_sensor *sensor = &tcm825x;
 853
 854        if (i2c_get_clientdata(client))
 855                return -EBUSY;
 856
 857        sensor->platform_data = client->dev.platform_data;
 858
 859        if (sensor->platform_data == NULL
 860            || !sensor->platform_data->is_okay())
 861                return -ENODEV;
 862
 863        sensor->v4l2_int_device = &tcm825x_int_device;
 864
 865        sensor->i2c_client = client;
 866        i2c_set_clientdata(client, sensor);
 867
 868        /* Make the default capture format QVGA RGB565 */
 869        sensor->pix.width = tcm825x_sizes[QVGA].width;
 870        sensor->pix.height = tcm825x_sizes[QVGA].height;
 871        sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
 872
 873        return v4l2_int_device_register(sensor->v4l2_int_device);
 874}
 875
 876static int tcm825x_remove(struct i2c_client *client)
 877{
 878        struct tcm825x_sensor *sensor = i2c_get_clientdata(client);
 879
 880        if (!client->adapter)
 881                return -ENODEV; /* our client isn't attached */
 882
 883        v4l2_int_device_unregister(sensor->v4l2_int_device);
 884
 885        return 0;
 886}
 887
 888static const struct i2c_device_id tcm825x_id[] = {
 889        { "tcm825x", 0 },
 890        { }
 891};
 892MODULE_DEVICE_TABLE(i2c, tcm825x_id);
 893
 894static struct i2c_driver tcm825x_i2c_driver = {
 895        .driver = {
 896                .name = TCM825X_NAME,
 897        },
 898        .probe  = tcm825x_probe,
 899        .remove = tcm825x_remove,
 900        .id_table = tcm825x_id,
 901};
 902
 903static struct tcm825x_sensor tcm825x = {
 904        .timeperframe = {
 905                .numerator   = 1,
 906                .denominator = DEFAULT_FPS,
 907        },
 908};
 909
 910static int __init tcm825x_init(void)
 911{
 912        int rval;
 913
 914        rval = i2c_add_driver(&tcm825x_i2c_driver);
 915        if (rval)
 916                printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",
 917                       __func__);
 918
 919        return rval;
 920}
 921
 922static void __exit tcm825x_exit(void)
 923{
 924        i2c_del_driver(&tcm825x_i2c_driver);
 925}
 926
 927/*
 928 * FIXME: Menelaus isn't ready (?) at module_init stage, so use
 929 * late_initcall for now.
 930 */
 931late_initcall(tcm825x_init);
 932module_exit(tcm825x_exit);
 933
 934MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
 935MODULE_DESCRIPTION("TCM825x camera sensor driver");
 936MODULE_LICENSE("GPL");
 937