Logo Search packages:      
Sourcecode: linux-fsl-imx51 version File versions  Download package

adv7180.c

Go to the documentation of this file.
/*
 * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
 */

/*
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */

/*!
 * @file adv7180.c
 *
 * @brief Analog Device ADV7180 video decoder functions
 *
 * @ingroup Camera
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/wait.h>
#include <linux/videodev2.h>
#include <linux/workqueue.h>
#include <linux/regulator/consumer.h>
#include <media/v4l2-int-device.h>
#include <mach/hardware.h>
#include "mxc_v4l2_capture.h"

static struct regulator *dvddio_regulator;
static struct regulator *dvdd_regulator;
static struct regulator *avdd_regulator;
static struct regulator *pvdd_regulator;

extern void gpio_sensor_active(void);
extern void gpio_sensor_inactive(void);

static int adv7180_probe(struct i2c_client *adapter,
                   const struct i2c_device_id *id);
static int adv7180_detach(struct i2c_client *client);

static const struct i2c_device_id adv7180_id[] = {
      {"adv7180", 0},
      {},
};

MODULE_DEVICE_TABLE(i2c, adv7180_id);

static struct i2c_driver adv7180_i2c_driver = {
      .driver = {
               .owner = THIS_MODULE,
               .name = "adv7180",
               },
      .probe = adv7180_probe,
      .remove = adv7180_detach,
      .id_table = adv7180_id,
};

/*!
 * Maintains the information on the current state of the sesor.
 */
00070 struct sensor {
      struct v4l2_int_device *v4l2_int_device;
      struct i2c_client *i2c_client;
      struct v4l2_pix_format pix;
      struct v4l2_captureparm streamcap;
      bool on;

      /* control settings */
      int brightness;
      int hue;
      int contrast;
      int saturation;
      int red;
      int green;
      int blue;
      int ae_mode;

      v4l2_std_id std_id;
} adv7180_data;

/*! List of input video formats supported. The video formats is corresponding
 * with v4l2 id in video_fmt_t
 */
00093 typedef enum {
00094       ADV7180_NTSC = 0, /*!< Locked on (M) NTSC video signal. */
00095       ADV7180_PAL,            /*!< (B, G, H, I, N)PAL video signal. */
00096       ADV7180_NOT_LOCKED,     /*!< Not locked on a signal. */
} video_fmt_idx;

/*! Number of video standards supported (including 'not locked' signal). */
00100 #define ADV7180_STD_MAX       (ADV7180_PAL + 1)

/*! Video format structure. */
00103 typedef struct {
00104       int v4l2_id;            /*!< Video for linux ID. */
00105       char name[16];          /*!< Name (e.g., "NTSC", "PAL", etc.) */
00106       u16 raw_width;          /*!< Raw width. */
00107       u16 raw_height;         /*!< Raw height. */
00108       u16 active_width; /*!< Active width. */
00109       u16 active_height;      /*!< Active height. */
} video_fmt_t;

/*! Description of video formats supported.
 *
 *  PAL: raw=720x625, active=720x576.
 *  NTSC: raw=720x525, active=720x480.
 */
00117 static video_fmt_t video_fmts[] = {
      {                 /*! NTSC */
       .v4l2_id = V4L2_STD_NTSC,
       .name = "NTSC",
       .raw_width = 720 - 1,  /* SENS_FRM_WIDTH */
       .raw_height = 288 - 1, /* SENS_FRM_HEIGHT */
       .active_width = 720,   /* ACT_FRM_WIDTH plus 1 */
       .active_height = (480 / 2),  /* ACT_FRM_WIDTH plus 1 */
       },
      {                 /*! (B, G, H, I, N) PAL */
       .v4l2_id = V4L2_STD_PAL,
       .name = "PAL",
       .raw_width = 720 - 1,
       .raw_height = (576 / 2) + 24 * 2 - 1,
       .active_width = 720,
       .active_height = (576 / 2),
       },
      {                 /*! Unlocked standard */
       .v4l2_id = V4L2_STD_ALL,
       .name = "Autodetect",
       .raw_width = 720 - 1,
       .raw_height = (576 / 2) + 24 * 2 - 1,
       .active_width = 720,
       .active_height = (576 / 2),
       },
};

/*!* Standard index of ADV7180. */
00145 static video_fmt_idx video_idx = ADV7180_PAL;

/*! @brief This mutex is used to provide mutual exclusion.
 *
 *  Create a mutex that can be used to provide mutually exclusive
 *  read/write access to the globally accessible data structures
 *  and variables that were defined above.
 */
static DECLARE_MUTEX(mutex);

#define IF_NAME                    "adv7180"
#define ADV7180_INPUT_CTL              0x00     /* Input Control */
#define ADV7180_STATUS_1               0x10     /* Status #1 */
#define ADV7180_BRIGHTNESS             0x0a     /* Brightness */
#define ADV7180_IDENT                  0x11     /* IDENT */
#define ADV7180_VSYNC_FIELD_CTL_1      0x31     /* VSYNC Field Control #1 */
#define ADV7180_MANUAL_WIN_CTL         0x3d     /* Manual Window Control */
#define ADV7180_SD_SATURATION_CB       0xe3     /* SD Saturation Cb */
#define ADV7180_SD_SATURATION_CR       0xe4     /* SD Saturation Cr */
#define ADV7180_PWR_MNG                0x0f     /* Power Management */

/* supported controls */
/* This hasn't been fully implemented yet.
 * This is how it should work, though. */
static struct v4l2_queryctrl adv7180_qctrl[] = {
      {
      .id = V4L2_CID_BRIGHTNESS,
      .type = V4L2_CTRL_TYPE_INTEGER,
      .name = "Brightness",
      .minimum = 0,           /* check this value */
      .maximum = 255,         /* check this value */
      .step = 1,        /* check this value */
      .default_value = 127,   /* check this value */
      .flags = 0,
      }, {
      .id = V4L2_CID_SATURATION,
      .type = V4L2_CTRL_TYPE_INTEGER,
      .name = "Saturation",
      .minimum = 0,           /* check this value */
      .maximum = 255,         /* check this value */
      .step = 0x1,            /* check this value */
      .default_value = 127,   /* check this value */
      .flags = 0,
      }
};

/***********************************************************************
 * I2C transfert.
 ***********************************************************************/

/*! Read one register from a ADV7180 i2c slave device.
 *
 *  @param *reg         register in the device we wish to access.
 *
 *  @return              0 if success, an error code otherwise.
 */
00201 static inline int adv7180_read(u8 reg)
{
      int val;
      val = i2c_smbus_read_byte_data(adv7180_data.i2c_client, reg);
      if (val < 0) {
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "%s:read reg error: reg=%2x \n", __func__, reg);
            return -1;
      }
      return val;
}

/*! Write one register of a ADV7180 i2c slave device.
 *
 *  @param *reg         register in the device we wish to access.
 *
 *  @return              0 if success, an error code otherwise.
 */
00219 static int adv7180_write_reg(u8 reg, u8 val)
{
      if (i2c_smbus_write_byte_data(adv7180_data.i2c_client, reg, val) < 0) {
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "%s:write reg error:reg=%2x,val=%2x\n", __func__,
                  reg, val);
            return -1;
      }
      return 0;
}

/***********************************************************************
 * mxc_v4l2_capture interface.
 ***********************************************************************/

/*!
 * Return attributes of current video standard.
 * Since this device autodetects the current standard, this function also
 * sets the values that need to be changed if the standard changes.
 * There is no set std equivalent function.
 *
 *  @return       None.
 */
00242 static void adv7180_get_std(v4l2_std_id *std)
{
      int tmp;
      int idx;

      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180_get_std\n");

      /* Read the AD_RESULT to get the detect output video standard */
      tmp = adv7180_read(ADV7180_STATUS_1) & 0x70;

      down(&mutex);
      if (tmp == 0x40) {
            /* PAL */
            *std = V4L2_STD_PAL;
            idx = ADV7180_PAL;
      } else if (tmp == 0) {
            /*NTSC*/
            *std = V4L2_STD_NTSC;
            idx = ADV7180_NTSC;
      } else {
            *std = V4L2_STD_ALL;
            idx = ADV7180_NOT_LOCKED;
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "Got invalid video standard! \n");
      }
      up(&mutex);

      /* This assumes autodetect which this device uses. */
      if (*std != adv7180_data.std_id) {
            video_idx = idx;
            adv7180_data.std_id = *std;
            adv7180_data.pix.width = video_fmts[video_idx].raw_width;
            adv7180_data.pix.height = video_fmts[video_idx].raw_height;
      }
}

/***********************************************************************
 * IOCTL Functions from v4l2_int_ioctl_desc.
 ***********************************************************************/

/*!
 * ioctl_g_ifparm - V4L2 sensor interface handler for vidioc_int_g_ifparm_num
 * s: pointer to standard V4L2 device structure
 * p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure
 *
 * Gets slave interface parameters.
 * Calculates the required xclk value to support the requested
 * clock parameters in p.  This value is returned in the p
 * parameter.
 *
 * vidioc_int_g_ifparm returns platform-specific information about the
 * interface settings used by the sensor.
 *
 * Called on open.
 */
00297 static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
{
      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_g_ifparm\n");

      if (s == NULL) {
            pr_err("   ERROR!! no slave device set!\n");
            return -1;
      }

      /* Initialize structure to 0s then set any non-0 values. */
      memset(p, 0, sizeof(*p));
      p->if_type = V4L2_IF_TYPE_BT656; /* This is the only possibility. */
      p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT;
      p->u.bt656.nobt_hs_inv = 1;

      /* ADV7180 has a dedicated clock so no clock settings needed. */

      return 0;
}

/*!
 * Sets the camera power.
 *
 * s  pointer to the camera device
 * on if 1, power is to be turned on.  0 means power is to be turned off
 *
 * ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num
 * @s: pointer to standard V4L2 device structure
 * @on: power state to which device is to be set
 *
 * Sets devices power state to requrested state, if possible.
 * This is called on open, close, suspend and resume.
 */
00330 static int ioctl_s_power(struct v4l2_int_device *s, int on)
{
      struct sensor *sensor = s->priv;

      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_s_power\n");

      if (on && !sensor->on) {
            gpio_sensor_active();
            if (adv7180_write_reg(ADV7180_PWR_MNG, 0) != 0)
                  return -EIO;
      } else if (!on && sensor->on) {
            if (adv7180_write_reg(ADV7180_PWR_MNG, 0x24) != 0)
                  return -EIO;
            gpio_sensor_inactive();
      }

      sensor->on = on;

      return 0;
}

/*!
 * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
 * @s: pointer to standard V4L2 device structure
 * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
 *
 * Returns the sensor's video CAPTURE parameters.
 */
00358 static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
{
      struct sensor *sensor = s->priv;
      struct v4l2_captureparm *cparm = &a->parm.capture;

      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_g_parm\n");

      switch (a->type) {
      /* These are all the possible cases. */
      case V4L2_BUF_TYPE_VIDEO_CAPTURE:
            pr_debug("   type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
            memset(a, 0, sizeof(*a));
            a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            cparm->capability = sensor->streamcap.capability;
            cparm->timeperframe = sensor->streamcap.timeperframe;
            cparm->capturemode = sensor->streamcap.capturemode;
            break;

      case V4L2_BUF_TYPE_VIDEO_OUTPUT:
      case V4L2_BUF_TYPE_VIDEO_OVERLAY:
      case V4L2_BUF_TYPE_VBI_CAPTURE:
      case V4L2_BUF_TYPE_VBI_OUTPUT:
      case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
      case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
            break;

      default:
            pr_debug("ioctl_g_parm:type is unknown %d\n", a->type);
            break;
      }

      return 0;
}

/*!
 * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
 * @s: pointer to standard V4L2 device structure
 * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
 *
 * Configures the sensor to use the input parameters, if possible.  If
 * not possible, reverts to the old parameters and returns the
 * appropriate error code.
 *
 * This driver cannot change these settings.
 */
00403 static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
{
      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_s_parm\n");

      switch (a->type) {
      /* These are all the possible cases. */
      case V4L2_BUF_TYPE_VIDEO_CAPTURE:
      case V4L2_BUF_TYPE_VIDEO_OUTPUT:
      case V4L2_BUF_TYPE_VIDEO_OVERLAY:
      case V4L2_BUF_TYPE_VBI_CAPTURE:
      case V4L2_BUF_TYPE_VBI_OUTPUT:
      case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
      case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
            break;

      default:
            pr_debug("   type is unknown - %d\n", a->type);
            break;
      }

      return 0;
}

/*!
 * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
 * @s: pointer to standard V4L2 device structure
 * @f: pointer to standard V4L2 v4l2_format structure
 *
 * Returns the sensor's current pixel format in the v4l2_format
 * parameter.
 */
00434 static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
{
      struct sensor *sensor = s->priv;

      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_g_fmt_cap\n");

      switch (f->type) {
      case V4L2_BUF_TYPE_VIDEO_CAPTURE:
            pr_debug("   Returning size of %dx%d\n",
                   sensor->pix.width, sensor->pix.height);
            f->fmt.pix = sensor->pix;
            break;

      case V4L2_BUF_TYPE_PRIVATE: {
            v4l2_std_id std;
            adv7180_get_std(&std);
            f->fmt.pix.pixelformat = (u32)std;
            }
            break;

      default:
            f->fmt.pix = sensor->pix;
            break;
      }

      return 0;
}

/*!
 * ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl
 * @s: pointer to standard V4L2 device structure
 * @qc: standard V4L2 VIDIOC_QUERYCTRL ioctl structure
 *
 * If the requested control is supported, returns the control information
 * from the video_control[] array.  Otherwise, returns -EINVAL if the
 * control is not supported.
 */
00471 static int ioctl_queryctrl(struct v4l2_int_device *s,
                     struct v4l2_queryctrl *qc)
{
      int i;

      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_queryctrl\n");

      for (i = 0; i < ARRAY_SIZE(adv7180_qctrl); i++)
            if (qc->id && qc->id == adv7180_qctrl[i].id) {
                  memcpy(qc, &(adv7180_qctrl[i]),
                        sizeof(*qc));
                  return (0);
            }

      return -EINVAL;
}

/*!
 * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
 * @s: pointer to standard V4L2 device structure
 * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
 *
 * If the requested control is supported, returns the control's current
 * value from the video_control[] array.  Otherwise, returns -EINVAL
 * if the control is not supported.
 */
00497 static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
{
      int ret = 0;

      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_g_ctrl\n");

      switch (vc->id) {
      case V4L2_CID_BRIGHTNESS:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_BRIGHTNESS\n");
            adv7180_data.brightness = adv7180_read(ADV7180_BRIGHTNESS);
            vc->value = adv7180_data.brightness;
            break;
      case V4L2_CID_CONTRAST:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_CONTRAST\n");
            vc->value = adv7180_data.contrast;
            break;
      case V4L2_CID_SATURATION:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_SATURATION\n");
            adv7180_data.saturation = adv7180_read(ADV7180_SD_SATURATION_CB);
            vc->value = adv7180_data.saturation;
            break;
      case V4L2_CID_HUE:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_HUE\n");
            vc->value = adv7180_data.hue;
            break;
      case V4L2_CID_AUTO_WHITE_BALANCE:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_AUTO_WHITE_BALANCE\n");
            break;
      case V4L2_CID_DO_WHITE_BALANCE:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_DO_WHITE_BALANCE\n");
            break;
      case V4L2_CID_RED_BALANCE:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_RED_BALANCE\n");
            vc->value = adv7180_data.red;
            break;
      case V4L2_CID_BLUE_BALANCE:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_BLUE_BALANCE\n");
            vc->value = adv7180_data.blue;
            break;
      case V4L2_CID_GAMMA:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_GAMMA\n");
            break;
      case V4L2_CID_EXPOSURE:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_EXPOSURE\n");
            vc->value = adv7180_data.ae_mode;
            break;
      case V4L2_CID_AUTOGAIN:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_AUTOGAIN\n");
            break;
      case V4L2_CID_GAIN:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_GAIN\n");
            break;
      case V4L2_CID_HFLIP:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_HFLIP\n");
            break;
      case V4L2_CID_VFLIP:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_VFLIP\n");
            break;
      default:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   Default case\n");
            vc->value = 0;
            ret = -EPERM;
            break;
      }

      return ret;
}

/*!
 * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
 * @s: pointer to standard V4L2 device structure
 * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
 *
 * If the requested control is supported, sets the control's current
 * value in HW (and updates the video_control[] array).  Otherwise,
 * returns -EINVAL if the control is not supported.
 */
00589 static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
{
      int retval = 0;
      u8 tmp;

      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_s_ctrl\n");

      switch (vc->id) {
      case V4L2_CID_BRIGHTNESS:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_BRIGHTNESS\n");
            tmp = vc->value;
            adv7180_write_reg(ADV7180_BRIGHTNESS, tmp);
            adv7180_data.brightness = vc->value;
            break;
      case V4L2_CID_CONTRAST:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_CONTRAST\n");
            break;
      case V4L2_CID_SATURATION:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_SATURATION\n");
            tmp = vc->value;
            adv7180_write_reg(ADV7180_SD_SATURATION_CB, tmp);
            adv7180_write_reg(ADV7180_SD_SATURATION_CR, tmp);
            adv7180_data.saturation = vc->value;
            break;
      case V4L2_CID_HUE:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_HUE\n");
            break;
      case V4L2_CID_AUTO_WHITE_BALANCE:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_AUTO_WHITE_BALANCE\n");
            break;
      case V4L2_CID_DO_WHITE_BALANCE:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_DO_WHITE_BALANCE\n");
            break;
      case V4L2_CID_RED_BALANCE:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_RED_BALANCE\n");
            break;
      case V4L2_CID_BLUE_BALANCE:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_BLUE_BALANCE\n");
            break;
      case V4L2_CID_GAMMA:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_GAMMA\n");
            break;
      case V4L2_CID_EXPOSURE:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_EXPOSURE\n");
            break;
      case V4L2_CID_AUTOGAIN:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_AUTOGAIN\n");
            break;
      case V4L2_CID_GAIN:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_GAIN\n");
            break;
      case V4L2_CID_HFLIP:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_HFLIP\n");
            break;
      case V4L2_CID_VFLIP:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   V4L2_CID_VFLIP\n");
            break;
      default:
            dev_dbg(&adv7180_data.i2c_client->dev,
                  "   Default case\n");
            retval = -EPERM;
            break;
      }

      return retval;
}

/*!
 * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
 * @s: pointer to standard V4L2 device structure
 */
00674 static int ioctl_init(struct v4l2_int_device *s)
{
      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_init\n");
      return 0;
}

/*!
 * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
 * @s: pointer to standard V4L2 device structure
 *
 * Initialise the device when slave attaches to the master.
 */
00686 static int ioctl_dev_init(struct v4l2_int_device *s)
{
      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_dev_init\n");
      return 0;
}

/*!
 * This structure defines all the ioctls for this module.
 */
00695 static struct v4l2_int_ioctl_desc adv7180_ioctl_desc[] = {

      {vidioc_int_dev_init_num, (v4l2_int_ioctl_func *)ioctl_dev_init},

      /*!
       * Delinitialise the dev. at slave detach.
       * The complement of ioctl_dev_init.
       */
/*    {vidioc_int_dev_exit_num, (v4l2_int_ioctl_func *)ioctl_dev_exit}, */

      {vidioc_int_s_power_num, (v4l2_int_ioctl_func *)ioctl_s_power},
      {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func *)ioctl_g_ifparm},
/*    {vidioc_int_g_needs_reset_num,
                        (v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */
/*    {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */
      {vidioc_int_init_num, (v4l2_int_ioctl_func *)ioctl_init},

      /*!
       * VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
       */
/*    {vidioc_int_enum_fmt_cap_num,
                        (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap}, */

      /*!
       * VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type.
       * This ioctl is used to negotiate the image capture size and
       * pixel format without actually making it take effect.
       */
/*    {vidioc_int_try_fmt_cap_num,
                        (v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */

      {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_g_fmt_cap},

      /*!
       * If the requested format is supported, configures the HW to use that
       * format, returns error code if format not supported or HW can't be
       * correctly configured.
       */
/*    {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, */

      {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *)ioctl_g_parm},
      {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *)ioctl_s_parm},
      {vidioc_int_queryctrl_num, (v4l2_int_ioctl_func *)ioctl_queryctrl},
      {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *)ioctl_g_ctrl},
      {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *)ioctl_s_ctrl},
};

static struct v4l2_int_slave adv7180_slave = {
      .ioctls = adv7180_ioctl_desc,
      .num_ioctls = ARRAY_SIZE(adv7180_ioctl_desc),
};

static struct v4l2_int_device adv7180_int_device = {
      .module = THIS_MODULE,
      .name = "adv7180",
      .type = v4l2_int_type_slave,
      .u = {
            .slave = &adv7180_slave,
      },
};


/***********************************************************************
 * I2C client and driver.
 ***********************************************************************/

/*! ADV7180 Reset function.
 *
 *  @return       None.
 */
00765 static void adv7180_hard_reset(void)
{
      dev_dbg(&adv7180_data.i2c_client->dev,
            "In adv7180:adv7180_hard_reset\n");

      /*! Driver works fine without explicit register
       * initialization. Furthermore, initializations takes about 2 seconds
       * at startup...
       */

      /*! Set YPbPr input on AIN1,4,5 and normal
       * operations(autodection of all stds).
       */
      adv7180_write_reg(ADV7180_INPUT_CTL, 0x09);

      /*! Datasheet recommends: */
      adv7180_write_reg(ADV7180_VSYNC_FIELD_CTL_1, 0x02);
      adv7180_write_reg(ADV7180_MANUAL_WIN_CTL, 0xa2);
}

/*! ADV7180 I2C attach function.
 *
 *  @param *adapter     struct i2c_adapter *.
 *
 *  @return       Error code indicating success or failure.
 */

/*!
 * ADV7180 I2C probe function.
 * Function set in i2c_driver struct.
 * Called by insmod.
 *
 *  @param *adapter     I2C adapter descriptor.
 *
 *  @return       Error code indicating success or failure.
 */
00801 static int adv7180_probe(struct i2c_client *client,
                   const struct i2c_device_id *id)
{
      int rev_id;
      int ret = 0;
      struct mxc_tvin_platform_data *plat_data = client->dev.platform_data;

      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180_probe\n");

      if (plat_data->dvddio_reg) {
            dvddio_regulator =
                regulator_get(&client->dev, plat_data->dvddio_reg);
            if (!IS_ERR_VALUE((unsigned long)dvddio_regulator)) {
                  regulator_set_voltage(dvddio_regulator, 3300000, 3300000);
                  if (regulator_enable(dvddio_regulator) != 0)
                        return -ENODEV;
            }
      }

      if (plat_data->dvdd_reg) {
            dvdd_regulator =
                regulator_get(&client->dev, plat_data->dvdd_reg);
            if (!IS_ERR_VALUE((unsigned long)dvdd_regulator)) {
                  regulator_set_voltage(dvdd_regulator, 1800000, 1800000);
                  if (regulator_enable(dvdd_regulator) != 0)
                        return -ENODEV;
            }
      }

      if (plat_data->avdd_reg) {
            avdd_regulator =
                regulator_get(&client->dev, plat_data->avdd_reg);
            if (!IS_ERR_VALUE((unsigned long)avdd_regulator)) {
                  regulator_set_voltage(avdd_regulator, 1800000, 1800000);
                  if (regulator_enable(avdd_regulator) != 0)
                        return -ENODEV;
            }
      }

      if (plat_data->pvdd_reg) {
            pvdd_regulator =
                regulator_get(&client->dev, plat_data->pvdd_reg);
            if (!IS_ERR_VALUE((unsigned long)pvdd_regulator)) {
                  regulator_set_voltage(pvdd_regulator, 1800000, 1800000);
                  if (regulator_enable(pvdd_regulator) != 0)
                        return -ENODEV;
            }
      }

      if (plat_data->reset)
            plat_data->reset();

      if (plat_data->pwdn)
            plat_data->pwdn(1);

      msleep(1);

      /* Set initial values for the sensor struct. */
      memset(&adv7180_data, 0, sizeof(adv7180_data));
      adv7180_data.i2c_client = client;
      adv7180_data.streamcap.timeperframe.denominator = 30;
      adv7180_data.streamcap.timeperframe.numerator = 1;
      adv7180_data.std_id = V4L2_STD_ALL;
      video_idx = ADV7180_NOT_LOCKED;
      adv7180_data.pix.width = video_fmts[video_idx].raw_width;
      adv7180_data.pix.height = video_fmts[video_idx].raw_height;
      adv7180_data.pix.pixelformat = V4L2_PIX_FMT_UYVY;  /* YUV422 */
      adv7180_data.pix.priv = 1;  /* 1 is used to indicate TV in */
      adv7180_data.on = true;

      gpio_sensor_active();

      dev_dbg(&adv7180_data.i2c_client->dev,
            "%s:adv7180 probe i2c address is 0x%02X \n",
            __func__, adv7180_data.i2c_client->addr);

      /*! Read the revision ID of the tvin chip */
      rev_id = adv7180_read(ADV7180_IDENT);
      dev_dbg(&adv7180_data.i2c_client->dev,
            "%s:Analog Device adv7%2X0 detected! \n", __func__,
            rev_id);

      /*! ADV7180 initialization. */
      adv7180_hard_reset();

      pr_debug("   type is %d (expect %d)\n",
             adv7180_int_device.type, v4l2_int_type_slave);
      pr_debug("   num ioctls is %d\n",
             adv7180_int_device.u.slave->num_ioctls);

      /* This function attaches this structure to the /dev/video0 device.
       * The pointer in priv points to the mt9v111_data structure here.*/
      adv7180_int_device.priv = &adv7180_data;
      ret = v4l2_int_device_register(&adv7180_int_device);

      return ret;
}

/*!
 * ADV7180 I2C detach function.
 * Called on rmmod.
 *
 *  @param *client      struct i2c_client*.
 *
 *  @return       Error code indicating success or failure.
 */
00907 static int adv7180_detach(struct i2c_client *client)
{
      struct mxc_tvin_platform_data *plat_data = client->dev.platform_data;

      dev_dbg(&adv7180_data.i2c_client->dev,
            "%s:Removing %s video decoder @ 0x%02X from adapter %s \n",
            __func__, IF_NAME, client->addr << 1, client->adapter->name);

      if (plat_data->pwdn)
            plat_data->pwdn(0);

      if (dvddio_regulator) {
            regulator_disable(dvddio_regulator);
            regulator_put(dvddio_regulator);
      }

      if (dvdd_regulator) {
            regulator_disable(dvdd_regulator);
            regulator_put(dvdd_regulator);
      }

      if (avdd_regulator) {
            regulator_disable(avdd_regulator);
            regulator_put(avdd_regulator);
      }

      if (pvdd_regulator) {
            regulator_disable(pvdd_regulator);
            regulator_put(pvdd_regulator);
      }

      v4l2_int_device_unregister(&adv7180_int_device);

      return 0;
}

/*!
 * ADV7180 init function.
 * Called on insmod.
 *
 * @return    Error code indicating success or failure.
 */
00949 static __init int adv7180_init(void)
{
      u8 err = 0;

      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180_init\n");

      /* Tells the i2c driver what functions to call for this driver. */
      err = i2c_add_driver(&adv7180_i2c_driver);
      if (err != 0)
            pr_err("%s:driver registration failed, error=%d \n",
                  __func__, err);

      return err;
}

/*!
 * ADV7180 cleanup function.
 * Called on rmmod.
 *
 * @return   Error code indicating success or failure.
 */
00970 static void __exit adv7180_clean(void)
{
      dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180_clean\n");
      i2c_del_driver(&adv7180_i2c_driver);
      gpio_sensor_inactive();
}

module_init(adv7180_init);
module_exit(adv7180_clean);

MODULE_AUTHOR("Freescale Semiconductor");
MODULE_DESCRIPTION("Anolog Device ADV7180 video decoder driver");
MODULE_LICENSE("GPL");

Generated by  Doxygen 1.6.0   Back to index