提交 1046a2c4 编写于 作者: L Linus Torvalds

Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (144 commits)
  [media] saa7134.h: Suppress compiler warnings when CONFIG_VIDEO_SAA7134_RC is not set
  [media] it913x [VER 1.07] Support for single ITE 9135 devices
  [media] Support for Terratec G1
  [media] cx25821: off by one in cx25821_vidioc_s_input()
  [media] media: tea5764: reconcile Kconfig symbol and macro
  [media] omap_vout: Add poll() support
  [media] omap3isp: preview: Add crop support on the sink pad
  [media] omap3isp: preview: Rename min/max input/output sizes defines
  [media] omap3isp: preview: Remove horizontal averager support
  [media] omap3isp: Report the ISP revision through the media controller API
  [media] omap3isp: ccdc: remove redundant operation
  [media] omap3isp: Fix memory leaks in initialization error paths
  [media] omap3isp: Add missing mutex_destroy() calls
  [media] omap3isp: Move *_init_entities() functions to the init/cleanup section
  [media] omap3isp: Move media_entity_cleanup() from unregister() to cleanup()
  [media] MFC: Change MFC firmware binary name
  [media] vb2: add vb2_get_unmapped_area in vb2 core
  [media] v4l: Add v4l2 subdev driver for S5K6AAFX sensor
  [media] v4l: Add AUTO option for the V4L2_CID_POWER_LINE_FREQUENCY control
  [media] media: ov6650: stylistic improvements
  ...
......@@ -2486,6 +2486,9 @@ ioctls.</para>
<listitem>
<para>Flash API. <xref linkend="flash-controls" /></para>
</listitem>
<listitem>
<para>&VIDIOC-CREATE-BUFS; and &VIDIOC-PREPARE-BUF; ioctls.</para>
</listitem>
</itemizedlist>
</section>
......
......@@ -232,8 +232,9 @@ control is deprecated. New drivers and applications should use the
<entry>Enables a power line frequency filter to avoid
flicker. Possible values for <constant>enum v4l2_power_line_frequency</constant> are:
<constant>V4L2_CID_POWER_LINE_FREQUENCY_DISABLED</constant> (0),
<constant>V4L2_CID_POWER_LINE_FREQUENCY_50HZ</constant> (1) and
<constant>V4L2_CID_POWER_LINE_FREQUENCY_60HZ</constant> (2).</entry>
<constant>V4L2_CID_POWER_LINE_FREQUENCY_50HZ</constant> (1),
<constant>V4L2_CID_POWER_LINE_FREQUENCY_60HZ</constant> (2) and
<constant>V4L2_CID_POWER_LINE_FREQUENCY_AUTO</constant> (3).</entry>
</row>
<row>
<entry><constant>V4L2_CID_HUE_AUTO</constant></entry>
......
......@@ -927,6 +927,33 @@ ioctl is called.</entry>
Applications set or clear this flag before calling the
<constant>VIDIOC_QBUF</constant> ioctl.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_PREPARED</constant></entry>
<entry>0x0400</entry>
<entry>The buffer has been prepared for I/O and can be queued by the
application. Drivers set or clear this flag when the
<link linkend="vidioc-querybuf">VIDIOC_QUERYBUF</link>, <link
linkend="vidioc-qbuf">VIDIOC_PREPARE_BUF</link>, <link
linkend="vidioc-qbuf">VIDIOC_QBUF</link> or <link
linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl is called.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry>
<entry>0x0400</entry>
<entry>Caches do not have to be invalidated for this buffer.
Typically applications shall use this flag if the data captured in the buffer
is not going to be touched by the CPU, instead the buffer will, probably, be
passed on to a DMA-capable hardware unit for further processing or output.
</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry>
<entry>0x0800</entry>
<entry>Caches do not have to be cleaned for this buffer.
Typically applications shall use this flag for output buffers if the data
in this buffer has not been created by the CPU but by some DMA-capable unit,
in which case caches have not been used.</entry>
</row>
</tbody>
</tgroup>
</table>
......
......@@ -469,6 +469,7 @@ and discussions on the V4L mailing list.</revremark>
&sub-close;
&sub-ioctl;
<!-- All ioctls go here. -->
&sub-create-bufs;
&sub-cropcap;
&sub-dbg-g-chip-ident;
&sub-dbg-g-register;
......@@ -511,6 +512,7 @@ and discussions on the V4L mailing list.</revremark>
&sub-queryctrl;
&sub-query-dv-preset;
&sub-querystd;
&sub-prepare-buf;
&sub-reqbufs;
&sub-s-hw-freq-seek;
&sub-streamon;
......
<refentry id="vidioc-create-bufs">
<refmeta>
<refentrytitle>ioctl VIDIOC_CREATE_BUFS</refentrytitle>
&manvol;
</refmeta>
<refnamediv>
<refname>VIDIOC_CREATE_BUFS</refname>
<refpurpose>Create buffers for Memory Mapped or User Pointer I/O</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcprototype>
<funcdef>int <function>ioctl</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>int <parameter>request</parameter></paramdef>
<paramdef>struct v4l2_create_buffers *<parameter>argp</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Arguments</title>
<variablelist>
<varlistentry>
<term><parameter>fd</parameter></term>
<listitem>
<para>&fd;</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>request</parameter></term>
<listitem>
<para>VIDIOC_CREATE_BUFS</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>argp</parameter></term>
<listitem>
<para></para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Description</title>
<para>This ioctl is used to create buffers for <link linkend="mmap">memory
mapped</link> or <link linkend="userp">user pointer</link>
I/O. It can be used as an alternative or in addition to the
<constant>VIDIOC_REQBUFS</constant> ioctl, when a tighter control over buffers
is required. This ioctl can be called multiple times to create buffers of
different sizes.</para>
<para>To allocate device buffers applications initialize relevant fields of
the <structname>v4l2_create_buffers</structname> structure. They set the
<structfield>type</structfield> field in the
<structname>v4l2_format</structname> structure, embedded in this
structure, to the respective stream or buffer type.
<structfield>count</structfield> must be set to the number of required buffers.
<structfield>memory</structfield> specifies the required I/O method. The
<structfield>format</structfield> field shall typically be filled in using
either the <constant>VIDIOC_TRY_FMT</constant> or
<constant>VIDIOC_G_FMT</constant> ioctl(). Additionally, applications can adjust
<structfield>sizeimage</structfield> fields to fit their specific needs. The
<structfield>reserved</structfield> array must be zeroed.</para>
<para>When the ioctl is called with a pointer to this structure the driver
will attempt to allocate up to the requested number of buffers and store the
actual number allocated and the starting index in the
<structfield>count</structfield> and the <structfield>index</structfield> fields
respectively. On return <structfield>count</structfield> can be smaller than
the number requested. The driver may also increase buffer sizes if required,
however, it will not update <structfield>sizeimage</structfield> field values.
The user has to use <constant>VIDIOC_QUERYBUF</constant> to retrieve that
information.</para>
<table pgwide="1" frame="none" id="v4l2-create-buffers">
<title>struct <structname>v4l2_create_buffers</structname></title>
<tgroup cols="3">
&cs-str;
<tbody valign="top">
<row>
<entry>__u32</entry>
<entry><structfield>index</structfield></entry>
<entry>The starting buffer index, returned by the driver.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>count</structfield></entry>
<entry>The number of buffers requested or granted.</entry>
</row>
<row>
<entry>&v4l2-memory;</entry>
<entry><structfield>memory</structfield></entry>
<entry>Applications set this field to
<constant>V4L2_MEMORY_MMAP</constant> or
<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
</row>
<row>
<entry>&v4l2-format;</entry>
<entry><structfield>format</structfield></entry>
<entry>Filled in by the application, preserved by the driver.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>reserved</structfield>[8]</entry>
<entry>A place holder for future extensions.</entry>
</row>
</tbody>
</tgroup>
</table>
</refsect1>
<refsect1>
&return-value;
<variablelist>
<varlistentry>
<term><errorcode>ENOMEM</errorcode></term>
<listitem>
<para>No memory to allocate buffers for <link linkend="mmap">memory
mapped</link> I/O.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><errorcode>EINVAL</errorcode></term>
<listitem>
<para>The buffer type (<structfield>type</structfield> field) or the
requested I/O method (<structfield>memory</structfield>) is not
supported.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
</refentry>
<refentry id="vidioc-prepare-buf">
<refmeta>
<refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle>
&manvol;
</refmeta>
<refnamediv>
<refname>VIDIOC_PREPARE_BUF</refname>
<refpurpose>Prepare a buffer for I/O</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcprototype>
<funcdef>int <function>ioctl</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>int <parameter>request</parameter></paramdef>
<paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Arguments</title>
<variablelist>
<varlistentry>
<term><parameter>fd</parameter></term>
<listitem>
<para>&fd;</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>request</parameter></term>
<listitem>
<para>VIDIOC_PREPARE_BUF</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>argp</parameter></term>
<listitem>
<para></para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Description</title>
<para>Applications can optionally call the
<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
to the driver before actually enqueuing it, using the
<constant>VIDIOC_QBUF</constant> ioctl, and to prepare it for future I/O.
Such preparations may include cache invalidation or cleaning. Performing them
in advance saves time during the actual I/O. In case such cache operations are
not required, the application can use one of
<constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant> and
<constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
step.</para>
<para>The <structname>v4l2_buffer</structname> structure is
specified in <xref linkend="buffer" />.</para>
</refsect1>
<refsect1>
&return-value;
<variablelist>
<varlistentry>
<term><errorcode>EBUSY</errorcode></term>
<listitem>
<para>File I/O is in progress.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><errorcode>EINVAL</errorcode></term>
<listitem>
<para>The buffer <structfield>type</structfield> is not
supported, or the <structfield>index</structfield> is out of bounds,
or no buffers have been allocated yet, or the
<structfield>userptr</structfield> or
<structfield>length</structfield> are invalid.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
</refentry>
......@@ -394,9 +394,9 @@ static int pcm990_camera_set_bus_param(struct soc_camera_link *link,
}
if (flags & SOCAM_DATAWIDTH_8)
gpio_set_value(gpio_bus_switch, 1);
gpio_set_value_cansleep(gpio_bus_switch, 1);
else
gpio_set_value(gpio_bus_switch, 0);
gpio_set_value_cansleep(gpio_bus_switch, 0);
return 0;
}
......
......@@ -933,7 +933,7 @@ static struct platform_device ap4evb_camera = {
static struct sh_csi2_client_config csi2_clients[] = {
{
.phy = SH_CSI2_PHY_MAIN,
.lanes = 3,
.lanes = 0, /* default: 2 lanes */
.channel = 0,
.pdev = &ap4evb_camera,
},
......
......@@ -1223,9 +1223,10 @@ static struct soc_camera_platform_info camera_info = {
.width = 640,
.height = 480,
},
.bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH |
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8 |
SOCAM_DATA_ACTIVE_HIGH,
.mbus_param = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH,
.mbus_type = V4L2_MBUS_PARALLEL,
.set_capture = camera_set_capture,
};
......
......@@ -345,9 +345,10 @@ static struct soc_camera_platform_info camera_info = {
.width = 640,
.height = 480,
},
.bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH |
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8 |
SOCAM_DATA_ACTIVE_HIGH,
.mbus_param = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH,
.mbus_type = V4L2_MBUS_PARALLEL,
.set_capture = camera_set_capture,
};
......@@ -501,8 +502,7 @@ static struct i2c_board_info ap325rxa_i2c_camera[] = {
};
static struct ov772x_camera_info ov7725_info = {
.flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP | \
OV772X_FLAG_8BIT,
.flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP,
.edgectrl = OV772X_AUTO_EDGECTRL(0xf, 0),
};
......
......@@ -448,9 +448,7 @@ static struct i2c_board_info migor_i2c_camera[] = {
},
};
static struct ov772x_camera_info ov7725_info = {
.flags = OV772X_FLAG_8BIT,
};
static struct ov772x_camera_info ov7725_info;
static struct soc_camera_link ov7725_link = {
.power = ov7725_power,
......
......@@ -1307,6 +1307,7 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
ipu_submit_buffer(ichan, descnew, sgnew, ichan->active_buffer) < 0) {
callback = descnew->txd.callback;
callback_param = descnew->txd.callback_param;
list_del_init(&descnew->list);
spin_unlock(&ichan->lock);
if (callback)
callback(callback_param);
......@@ -1428,39 +1429,58 @@ static int __idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
{
struct idmac_channel *ichan = to_idmac_chan(chan);
struct idmac *idmac = to_idmac(chan->device);
struct ipu *ipu = to_ipu(idmac);
struct list_head *list, *tmp;
unsigned long flags;
int i;
/* Only supports DMA_TERMINATE_ALL */
if (cmd != DMA_TERMINATE_ALL)
return -ENXIO;
switch (cmd) {
case DMA_PAUSE:
spin_lock_irqsave(&ipu->lock, flags);
ipu_ic_disable_task(ipu, chan->chan_id);
ipu_disable_channel(idmac, ichan,
ichan->status >= IPU_CHANNEL_ENABLED);
/* Return all descriptors into "prepared" state */
list_for_each_safe(list, tmp, &ichan->queue)
list_del_init(list);
tasklet_disable(&to_ipu(idmac)->tasklet);
ichan->sg[0] = NULL;
ichan->sg[1] = NULL;
/* ichan->queue is modified in ISR, have to spinlock */
spin_lock_irqsave(&ichan->lock, flags);
list_splice_init(&ichan->queue, &ichan->free_list);
spin_unlock_irqrestore(&ipu->lock, flags);
if (ichan->desc)
for (i = 0; i < ichan->n_tx_desc; i++) {
struct idmac_tx_desc *desc = ichan->desc + i;
if (list_empty(&desc->list))
/* Descriptor was prepared, but not submitted */
list_add(&desc->list, &ichan->free_list);
ichan->status = IPU_CHANNEL_INITIALIZED;
break;
case DMA_TERMINATE_ALL:
ipu_disable_channel(idmac, ichan,
ichan->status >= IPU_CHANNEL_ENABLED);
async_tx_clear_ack(&desc->txd);
}
tasklet_disable(&ipu->tasklet);
ichan->sg[0] = NULL;
ichan->sg[1] = NULL;
spin_unlock_irqrestore(&ichan->lock, flags);
/* ichan->queue is modified in ISR, have to spinlock */
spin_lock_irqsave(&ichan->lock, flags);
list_splice_init(&ichan->queue, &ichan->free_list);
tasklet_enable(&to_ipu(idmac)->tasklet);
if (ichan->desc)
for (i = 0; i < ichan->n_tx_desc; i++) {
struct idmac_tx_desc *desc = ichan->desc + i;
if (list_empty(&desc->list))
/* Descriptor was prepared, but not submitted */
list_add(&desc->list, &ichan->free_list);
ichan->status = IPU_CHANNEL_INITIALIZED;
async_tx_clear_ack(&desc->txd);
}
ichan->sg[0] = NULL;
ichan->sg[1] = NULL;
spin_unlock_irqrestore(&ichan->lock, flags);
tasklet_enable(&ipu->tasklet);
ichan->status = IPU_CHANNEL_INITIALIZED;
break;
default:
return -ENOSYS;
}
return 0;
}
......@@ -1663,7 +1683,6 @@ static void __exit ipu_idmac_exit(struct ipu *ipu)
struct idmac_channel *ichan = ipu->channel + i;
idmac_control(&ichan->dma_chan, DMA_TERMINATE_ALL, 0);
idmac_prep_slave_sg(&ichan->dma_chan, NULL, 0, DMA_NONE, 0);
}
dma_async_device_unregister(&idmac->dma);
......
......@@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/dvb/frontends/
ccflags-y += -Idrivers/media/common/tuners/
# For the staging CI driver cxd2099
ccflags-y += -Idrivers/staging/cxd2099/
ccflags-y += -Idrivers/staging/media/cxd2099/
......@@ -102,6 +102,7 @@ obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o
dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o
obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o
obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o
obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
......
......@@ -37,6 +37,7 @@
#define USB_VID_HAUPPAUGE 0x2040
#define USB_VID_HYPER_PALTEK 0x1025
#define USB_VID_INTEL 0x8086
#define USB_VID_ITETECH 0x048d
#define USB_VID_KWORLD 0xeb2a
#define USB_VID_KWORLD_2 0x1b80
#define USB_VID_KYE 0x0458
......@@ -126,6 +127,7 @@
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_INTEL_CE9500 0x9500
#define USB_PID_ITETECH_IT9135 0x9135
#define USB_PID_KWORLD_399U 0xe399
#define USB_PID_KWORLD_399U_2 0xe400
#define USB_PID_KWORLD_395U 0xe396
......
......@@ -60,6 +60,17 @@ struct it913x_state {
u8 id;
};
struct ite_config {
u8 chip_ver;
u16 chip_type;
u32 firmware;
u8 tuner_id_0;
u8 tuner_id_1;
u8 dual_mode;
};
struct ite_config it913x_config;
static int it913x_bulk_write(struct usb_device *dev,
u8 *snd, int len, u8 pipe)
{
......@@ -191,18 +202,23 @@ static int it913x_read_reg(struct usb_device *udev, u32 reg)
static u32 it913x_query(struct usb_device *udev, u8 pro)
{
int ret;
u32 res = 0;
u8 data[4];
ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ,
0x1222, 0, &data[0], 1);
if (data[0] == 0x1) {
ret = it913x_io(udev, READ_SHORT, pro,
0x1222, 0, &data[0], 3);
it913x_config.chip_ver = data[0];
it913x_config.chip_type = (u16)(data[2] << 8) + data[1];
info("Chip Version=%02x Chip Type=%04x", it913x_config.chip_ver,
it913x_config.chip_type);
ret |= it913x_io(udev, READ_SHORT, pro,
CMD_QUERYINFO, 0, 0x1, &data[0], 4);
res = (data[0] << 24) + (data[1] << 16) +
it913x_config.firmware = (data[0] << 24) + (data[1] << 16) +
(data[2] << 8) + data[3];
}
return (ret < 0) ? 0 : res;
return (ret < 0) ? 0 : it913x_config.firmware;
}
static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
......@@ -336,26 +352,35 @@ static int it913x_identify_state(struct usb_device *udev,
int *cold)
{
int ret = 0, firm_no;
u8 reg, adap, ep, tun0, tun1;
u8 reg, remote;
firm_no = it913x_return_status(udev);
ep = it913x_read_reg(udev, 0x49ac);
adap = it913x_read_reg(udev, 0x49c5);
tun0 = it913x_read_reg(udev, 0x49d0);
info("No. Adapters=%x Endpoints=%x Tuner Type=%x", adap, ep, tun0);
/* checnk for dual mode */
it913x_config.dual_mode = it913x_read_reg(udev, 0x49c5);
/* TODO different remotes */
remote = it913x_read_reg(udev, 0x49ac); /* Remote */
if (remote == 0)
props->rc.core.rc_codes = NULL;
/* TODO at the moment tuner_id is always assigned to 0x38 */
it913x_config.tuner_id_0 = it913x_read_reg(udev, 0x49d0);
info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode
, remote, it913x_config.tuner_id_0);
if (firm_no > 0) {
*cold = 0;
return 0;
}
if (adap > 2) {
tun1 = it913x_read_reg(udev, 0x49e0);
if (it913x_config.dual_mode) {
it913x_config.tuner_id_1 = it913x_read_reg(udev, 0x49e0);
ret = it913x_wr_reg(udev, DEV_0, GPIOH1_EN, 0x1);
ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_ON, 0x1);
ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1);
msleep(50); /* Delay noticed reset cycle ? */
msleep(50);
ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0);
msleep(50);
reg = it913x_read_reg(udev, GPIOH1_O);
......@@ -366,14 +391,19 @@ static int it913x_identify_state(struct usb_device *udev,
ret = it913x_wr_reg(udev, DEV_0,
GPIOH1_O, 0x0);
}
props->num_adapters = 2;
} else
props->num_adapters = 1;
reg = it913x_read_reg(udev, IO_MUX_POWER_CLK);
ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR);
ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1);
if (it913x_config.dual_mode) {
ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR);
ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1);
} else {
ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, 0x0);
ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x0);
}
*cold = 1;
......@@ -403,13 +433,11 @@ static int it913x_download_firmware(struct usb_device *udev,
const struct firmware *fw)
{
int ret = 0, i;
u8 packet_size, dlen, tun1;
u8 packet_size, dlen;
u8 *fw_data;
packet_size = 0x29;
tun1 = it913x_read_reg(udev, 0x49e0);
ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100);
info("FRM Starting Firmware Download");
......@@ -444,11 +472,12 @@ static int it913x_download_firmware(struct usb_device *udev,
ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400);
/* Tuner function */
ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0);
if (it913x_config.dual_mode)
ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0);
ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0);
ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0);
if (tun1 > 0) {
if (it913x_config.dual_mode) {
ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0);
ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0);
}
......@@ -475,9 +504,28 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK);
u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5);
u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize;
u8 tuner_id, tuner_type;
if (adap->id == 0)
tuner_id = it913x_config.tuner_id_0;
else
tuner_id = it913x_config.tuner_id_1;
/* TODO we always use IT9137 possible references here*/
/* Documentation suggests don't care */
switch (tuner_id) {
case 0x51:
case 0x52:
case 0x60:
case 0x61:
case 0x62:
default:
case 0x38:
tuner_type = IT9137;
}
adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach,
&adap->dev->i2c_adap, adap_addr, adf, IT9137);
&adap->dev->i2c_adap, adap_addr, adf, tuner_type);
if (adap->id == 0 && adap->fe_adap[0].fe) {
ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1);
......@@ -533,6 +581,7 @@ static int it913x_probe(struct usb_interface *intf,
static struct usb_device_id it913x_table[] = {
{ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) },
{ USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135) },
{} /* Terminating entry */
};
......@@ -608,12 +657,14 @@ static struct dvb_usb_device_properties it913x_properties = {
.rc_codes = RC_MAP_KWORLD_315U,
},
.i2c_algo = &it913x_i2c_algo,
.num_device_descs = 1,
.num_device_descs = 2,
.devices = {
{ "Kworld UB499-2T T09(IT9137)",
{ &it913x_table[0], NULL },
},
{ "ITE 9135 Generic",
{ &it913x_table[1], NULL },
},
}
};
......@@ -647,5 +698,5 @@ module_exit(it913x_module_exit);
MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
MODULE_DESCRIPTION("it913x USB 2 Driver");
MODULE_VERSION("1.06");
MODULE_VERSION("1.07");
MODULE_LICENSE("GPL");
/*
* mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator
*
* Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mxl111sf-demod.h"
#include "mxl111sf-reg.h"
/* debug */
static int mxl111sf_demod_debug;
module_param_named(debug, mxl111sf_demod_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
#define mxl_dbg(fmt, arg...) \
if (mxl111sf_demod_debug) \
mxl_printk(KERN_DEBUG, fmt, ##arg)
/* ------------------------------------------------------------------------ */
struct mxl111sf_demod_state {
struct mxl111sf_state *mxl_state;
struct mxl111sf_demod_config *cfg;
struct dvb_frontend fe;
};
/* ------------------------------------------------------------------------ */
static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state,
u8 addr, u8 *data)
{
return (state->cfg->read_reg) ?
state->cfg->read_reg(state->mxl_state, addr, data) :
-EINVAL;
}
static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state,
u8 addr, u8 data)
{
return (state->cfg->write_reg) ?
state->cfg->write_reg(state->mxl_state, addr, data) :
-EINVAL;
}
static
int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state,
struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
{
return (state->cfg->program_regs) ?
state->cfg->program_regs(state->mxl_state, ctrl_reg_info) :
-EINVAL;
}
/* ------------------------------------------------------------------------ */
/* TPS */
static
int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state,
fe_code_rate_t *code_rate)
{
u8 val;
int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val);
/* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */
if (mxl_fail(ret))
goto fail;
switch (val & V6_CODE_RATE_TPS_MASK) {
case 0:
*code_rate = FEC_1_2;
break;
case 1:
*code_rate = FEC_2_3;
break;
case 2:
*code_rate = FEC_3_4;
break;
case 3:
*code_rate = FEC_5_6;
break;
case 4:
*code_rate = FEC_7_8;
break;
}
fail:
return ret;
}
static
int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state,
fe_modulation_t *constellation)
{
u8 val;
int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val);
/* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */
if (mxl_fail(ret))
goto fail;
switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) {
case 0:
*constellation = QPSK;
break;
case 1:
*constellation = QAM_16;
break;
case 2:
*constellation = QAM_64;
break;
}
fail:
return ret;
}
static
int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state,
fe_transmit_mode_t *fft_mode)
{
u8 val;
int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val);
/* FFT Mode, 00:2K, 01:8K, 10:4K */
if (mxl_fail(ret))
goto fail;
switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) {
case 0:
*fft_mode = TRANSMISSION_MODE_2K;
break;
case 1:
*fft_mode = TRANSMISSION_MODE_8K;
break;
case 2:
*fft_mode = TRANSMISSION_MODE_4K;
break;
}
fail:
return ret;
}
static
int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state,
fe_guard_interval_t *guard)
{
u8 val;
int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val);
/* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */
if (mxl_fail(ret))
goto fail;
switch ((val & V6_PARAM_GI_MASK) >> 4) {
case 0:
*guard = GUARD_INTERVAL_1_32;
break;
case 1:
*guard = GUARD_INTERVAL_1_16;
break;
case 2:
*guard = GUARD_INTERVAL_1_8;
break;
case 3:
*guard = GUARD_INTERVAL_1_4;
break;
}
fail:
return ret;
}
static
int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state,
fe_hierarchy_t *hierarchy)
{
u8 val;
int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val);
/* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */
if (mxl_fail(ret))
goto fail;
switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) {
case 0:
*hierarchy = HIERARCHY_NONE;
break;
case 1:
*hierarchy = HIERARCHY_1;
break;
case 2:
*hierarchy = HIERARCHY_2;
break;
case 3:
*hierarchy = HIERARCHY_4;
break;
}
fail:
return ret;
}
/* ------------------------------------------------------------------------ */
/* LOCKS */
static
int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state,
int *sync_lock)
{
u8 val = 0;
int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val);
if (mxl_fail(ret))
goto fail;
*sync_lock = (val & SYNC_LOCK_MASK) >> 4;
fail:
return ret;
}
static
int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state,
int *rs_lock)
{
u8 val = 0;
int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val);
if (mxl_fail(ret))
goto fail;
*rs_lock = (val & RS_LOCK_DET_MASK) >> 3;
fail:
return ret;
}
static
int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state,
int *tps_lock)
{
u8 val = 0;
int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val);
if (mxl_fail(ret))
goto fail;
*tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6;
fail:
return ret;
}
static
int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state,
int *fec_lock)
{
u8 val = 0;
int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val);
if (mxl_fail(ret))
goto fail;
*fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4;
fail:
return ret;
}
#if 0
static
int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state,
int *cp_lock)
{
u8 val = 0;
int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val);
if (mxl_fail(ret))
goto fail;
*cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2;
fail:
return ret;
}
#endif
static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state)
{
return mxl111sf_demod_write_reg(state, 0x0e, 0xff);
}
/* ------------------------------------------------------------------------ */
static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *param)
{
struct mxl111sf_demod_state *state = fe->demodulator_priv;
int ret = 0;
struct mxl111sf_reg_ctrl_info phy_pll_patch[] = {
{0x00, 0xff, 0x01}, /* change page to 1 */
{0x40, 0xff, 0x05},
{0x40, 0xff, 0x01},
{0x41, 0xff, 0xca},
{0x41, 0xff, 0xc0},
{0x00, 0xff, 0x00}, /* change page to 0 */
{0, 0, 0}
};
mxl_dbg("()");
if (fe->ops.tuner_ops.set_params) {
ret = fe->ops.tuner_ops.set_params(fe, param);
if (mxl_fail(ret))
goto fail;
msleep(50);
}
ret = mxl111sf_demod_program_regs(state, phy_pll_patch);
mxl_fail(ret);
msleep(50);
ret = mxl1x1sf_demod_reset_irq_status(state);
mxl_fail(ret);
msleep(100);
fail:
return ret;
}
/* ------------------------------------------------------------------------ */
#if 0
/* resets TS Packet error count */
/* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */
static
int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state)
{
struct mxl111sf_reg_ctrl_info reset_per_count[] = {
{0x20, 0x01, 0x01},
{0x20, 0x01, 0x00},
{0, 0, 0}
};
return mxl111sf_demod_program_regs(state, reset_per_count);
}
#endif
/* returns TS Packet error count */
/* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */
static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
struct mxl111sf_demod_state *state = fe->demodulator_priv;
u32 fec_per_count, fec_per_scale;
u8 val;
int ret;
*ucblocks = 0;
/* FEC_PER_COUNT Register */
ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val);
if (mxl_fail(ret))
goto fail;
fec_per_count = val;
/* FEC_PER_SCALE Register */
ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val);
if (mxl_fail(ret))
goto fail;
val &= V6_FEC_PER_SCALE_MASK;
val *= 4;
fec_per_scale = 1 << val;
fec_per_count *= fec_per_scale;
*ucblocks = fec_per_count;
fail:
return ret;
}
#ifdef MXL111SF_DEMOD_ENABLE_CALCULATIONS
/* FIXME: leaving this enabled breaks the build on some architectures,
* and we shouldn't have any floating point math in the kernel, anyway.
*
* These macros need to be re-written, but it's harmless to simply
* return zero for now. */
#define CALCULATE_BER(avg_errors, count) \
((u32)(avg_errors * 4)/(count*64*188*8))
#define CALCULATE_SNR(data) \
((u32)((10 * (u32)data / 64) - 2.5))
#else
#define CALCULATE_BER(avg_errors, count) 0
#define CALCULATE_SNR(data) 0
#endif
static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct mxl111sf_demod_state *state = fe->demodulator_priv;
u8 val1, val2, val3;
int ret;
*ber = 0;
ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3);
if (mxl_fail(ret))
goto fail;
*ber = CALCULATE_BER((val1 | (val2 << 8)), val3);
fail:
return ret;
}
static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state,
u16 *snr)
{
u8 val1, val2;
int ret;
*snr = 0;
ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2);
if (mxl_fail(ret))
goto fail;
*snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8));
fail:
return ret;
}
static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct mxl111sf_demod_state *state = fe->demodulator_priv;
int ret = mxl111sf_demod_calc_snr(state, snr);
if (mxl_fail(ret))
goto fail;
*snr /= 10; /* 0.1 dB */
fail:
return ret;
}
static int mxl111sf_demod_read_status(struct dvb_frontend *fe,
fe_status_t *status)
{
struct mxl111sf_demod_state *state = fe->demodulator_priv;
int ret, locked, cr_lock, sync_lock, fec_lock;
*status = 0;
ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked);
if (mxl_fail(ret))
goto fail;
ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock);
if (mxl_fail(ret))
goto fail;
ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock);
if (mxl_fail(ret))
goto fail;
ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock);
if (mxl_fail(ret))
goto fail;
if (locked)
*status |= FE_HAS_SIGNAL;
if (cr_lock)
*status |= FE_HAS_CARRIER;
if (sync_lock)
*status |= FE_HAS_SYNC;
if (fec_lock) /* false positives? */
*status |= FE_HAS_VITERBI;
if ((locked) && (cr_lock) && (sync_lock))
*status |= FE_HAS_LOCK;
fail:
return ret;
}
static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe,
u16 *signal_strength)
{
struct mxl111sf_demod_state *state = fe->demodulator_priv;
fe_modulation_t constellation;
u16 snr;
mxl111sf_demod_calc_snr(state, &snr);
mxl1x1sf_demod_get_tps_constellation(state, &constellation);
switch (constellation) {
case QPSK:
*signal_strength = (snr >= 1300) ?
min(65535, snr * 44) : snr * 38;
break;
case QAM_16:
*signal_strength = (snr >= 1500) ?
min(65535, snr * 38) : snr * 33;
break;
case QAM_64:
*signal_strength = (snr >= 2000) ?
min(65535, snr * 29) : snr * 25;
break;
default:
*signal_strength = 0;
return -EINVAL;
}
return 0;
}
static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct mxl111sf_demod_state *state = fe->demodulator_priv;
mxl_dbg("()");
#if 0
p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF;
#endif
if (fe->ops.tuner_ops.get_bandwidth)
fe->ops.tuner_ops.get_bandwidth(fe, &p->u.ofdm.bandwidth);
if (fe->ops.tuner_ops.get_frequency)
fe->ops.tuner_ops.get_frequency(fe, &p->frequency);
mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_HP);
mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_LP);
mxl1x1sf_demod_get_tps_constellation(state, &p->u.ofdm.constellation);
mxl1x1sf_demod_get_tps_guard_fft_mode(state,
&p->u.ofdm.transmission_mode);
mxl1x1sf_demod_get_tps_guard_interval(state,
&p->u.ofdm.guard_interval);
mxl1x1sf_demod_get_tps_hierarchy(state,
&p->u.ofdm.hierarchy_information);
return 0;
}
static
int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 1000;
return 0;
}
static void mxl111sf_demod_release(struct dvb_frontend *fe)
{
struct mxl111sf_demod_state *state = fe->demodulator_priv;
mxl_dbg("()");
kfree(state);
fe->demodulator_priv = NULL;
}
static struct dvb_frontend_ops mxl111sf_demod_ops = {
.info = {
.name = "MaxLinear MxL111SF DVB-T demodulator",
.type = FE_OFDM,
.frequency_min = 177000000,
.frequency_max = 858000000,
.frequency_stepsize = 166666,
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
FE_CAN_QAM_AUTO |
FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
},
.release = mxl111sf_demod_release,
#if 0
.init = mxl111sf_init,
.i2c_gate_ctrl = mxl111sf_i2c_gate_ctrl,
#endif
.set_frontend = mxl111sf_demod_set_frontend,
.get_frontend = mxl111sf_demod_get_frontend,
.get_tune_settings = mxl111sf_demod_get_tune_settings,
.read_status = mxl111sf_demod_read_status,
.read_signal_strength = mxl111sf_demod_read_signal_strength,
.read_ber = mxl111sf_demod_read_ber,
.read_snr = mxl111sf_demod_read_snr,
.read_ucblocks = mxl111sf_demod_read_ucblocks,
};
struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
struct mxl111sf_demod_config *cfg)
{
struct mxl111sf_demod_state *state = NULL;
mxl_dbg("()");
state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL);
if (state == NULL)
return NULL;
state->mxl_state = mxl_state;
state->cfg = cfg;
memcpy(&state->fe.ops, &mxl111sf_demod_ops,
sizeof(struct dvb_frontend_ops));
state->fe.demodulator_priv = state;
return &state->fe;
}
EXPORT_SYMBOL_GPL(mxl111sf_demod_attach);
MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver");
MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
/*
* mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator
*
* Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __MXL111SF_DEMOD_H__
#define __MXL111SF_DEMOD_H__
#include "dvb_frontend.h"
#include "mxl111sf.h"
struct mxl111sf_demod_config {
int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data);
int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data);
int (*program_regs)(struct mxl111sf_state *state,
struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
};
#if defined(CONFIG_DVB_USB_MXL111SF) || \
(defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE))
extern
struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
struct mxl111sf_demod_config *cfg);
#else
static inline
struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
struct mxl111sf_demod_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif /* CONFIG_DVB_USB_MXL111SF */
#endif /* __MXL111SF_DEMOD_H__ */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
......@@ -17,6 +17,7 @@
#include "mxl111sf-i2c.h"
#include "mxl111sf-gpio.h"
#include "mxl111sf-demod.h"
#include "mxl111sf-tuner.h"
#include "lgdt3305.h"
......@@ -362,6 +363,22 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
return ret;
}
static int mxl111sf_ep4_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
struct dvb_usb_device *d = adap->dev;
struct mxl111sf_state *state = d->priv;
int ret = 0;
deb_info("%s(%d)\n", __func__, onoff);
if (onoff) {
ret = mxl111sf_enable_usb_output(state);
mxl_fail(ret);
}
return ret;
}
/* ------------------------------------------------------------------------ */
static struct lgdt3305_config hauppauge_lgdt3305_config = {
......@@ -438,6 +455,70 @@ static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap)
return ret;
}
static struct mxl111sf_demod_config mxl_demod_config = {
.read_reg = mxl111sf_read_reg,
.write_reg = mxl111sf_write_reg,
.program_regs = mxl111sf_ctrl_program_regs,
};
static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *d = adap->dev;
struct mxl111sf_state *state = d->priv;
int fe_id = adap->num_frontends_initialized;
struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
int ret;
deb_adv("%s()\n", __func__);
/* save a pointer to the dvb_usb_device in device state */
state->d = d;
adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2;
state->alt_mode = adap_state->alt_mode;
if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
err("set interface failed");
state->gpio_mode = MXL111SF_GPIO_MOD_DVBT;
adap_state->gpio_mode = state->gpio_mode;
adap_state->device_mode = MXL_SOC_MODE;
adap_state->ep6_clockphase = 1;
ret = mxl1x1sf_soft_reset(state);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_init_tuner_demod(state);
if (mxl_fail(ret))
goto fail;
ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
if (mxl_fail(ret))
goto fail;
ret = mxl111sf_enable_usb_output(state);
if (mxl_fail(ret))
goto fail;
ret = mxl1x1sf_top_master_ctrl(state, 1);
if (mxl_fail(ret))
goto fail;
/* dont care if this fails */
mxl111sf_init_port_expander(state);
adap->fe_adap[fe_id].fe = dvb_attach(mxl111sf_demod_attach, state,
&mxl_demod_config);
if (adap->fe_adap[fe_id].fe) {
adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
return 0;
}
ret = -EIO;
fail:
return ret;
}
static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state,
int antpath)
{
......@@ -567,7 +648,8 @@ struct i2c_algorithm mxl111sf_i2c_algo = {
#endif
};
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties;
static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties;
static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties;
static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties;
......@@ -580,8 +662,14 @@ static int mxl111sf_probe(struct usb_interface *intf,
if (((dvb_usb_mxl111sf_isoc) &&
(0 == dvb_usb_device_init(intf,
&mxl111sf_dvbt_isoc_properties,
THIS_MODULE, &d, adapter_nr) ||
0 == dvb_usb_device_init(intf,
&mxl111sf_atsc_isoc_properties,
THIS_MODULE, &d, adapter_nr))) ||
0 == dvb_usb_device_init(intf,
&mxl111sf_dvbt_bulk_properties,
THIS_MODULE, &d, adapter_nr) ||
0 == dvb_usb_device_init(intf,
&mxl111sf_atsc_bulk_properties,
THIS_MODULE, &d, adapter_nr) || 0) {
......@@ -669,6 +757,36 @@ static struct usb_device_id mxl111sf_table[] = {
MODULE_DEVICE_TABLE(usb, mxl111sf_table);
#define MXL111SF_EP4_BULK_STREAMING_CONFIG \
.streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \
.stream = { \
.type = USB_BULK, \
.count = 5, \
.endpoint = 0x04, \
.u = { \
.bulk = { \
.buffersize = 8192, \
} \
} \
}
/* FIXME: works for v6 but not v8 silicon */
#define MXL111SF_EP4_ISOC_STREAMING_CONFIG \
.streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \
.stream = { \
.type = USB_ISOC, \
.count = 5, \
.endpoint = 0x04, \
.u = { \
.isoc = { \
.framesperurb = 96, \
/* FIXME: v6 SILICON: */ \
.framesize = 564, \
.interval = 1, \
} \
} \
}
#define MXL111SF_EP6_BULK_STREAMING_CONFIG \
.streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \
.stream = { \
......@@ -712,7 +830,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table);
.generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \
.size_of_priv = sizeof(struct mxl111sf_state)
static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = {
MXL111SF_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
......@@ -723,10 +841,106 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
.fe = {{
.size_of_priv = sizeof(struct mxl111sf_adap_state),
.frontend_attach = mxl111sf_attach_demod,
.tuner_attach = mxl111sf_attach_tuner,
MXL111SF_EP4_BULK_STREAMING_CONFIG,
} },
},
},
.num_device_descs = 4,
.devices = {
{ "Hauppauge 126xxx DVBT (bulk)",
{ NULL },
{ &mxl111sf_table[4], &mxl111sf_table[8],
NULL },
},
{ "Hauppauge 117xxx DVBT (bulk)",
{ NULL },
{ &mxl111sf_table[15], &mxl111sf_table[18],
NULL },
},
{ "Hauppauge 138xxx DVBT (bulk)",
{ NULL },
{ &mxl111sf_table[20], &mxl111sf_table[22],
&mxl111sf_table[24], &mxl111sf_table[26],
NULL },
},
{ "Hauppauge 126xxx (tp-bulk)",
{ NULL },
{ &mxl111sf_table[28], &mxl111sf_table[30],
NULL },
},
}
};
static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = {
MXL111SF_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
{
.fe_ioctl_override = mxl111sf_fe_ioctl_override,
.num_frontends = 1,
.fe = {{
.size_of_priv = sizeof(struct mxl111sf_adap_state),
.frontend_attach = mxl111sf_attach_demod,
.tuner_attach = mxl111sf_attach_tuner,
MXL111SF_EP4_ISOC_STREAMING_CONFIG,
} },
},
},
.num_device_descs = 4,
.devices = {
{ "Hauppauge 126xxx DVBT (isoc)",
{ NULL },
{ &mxl111sf_table[4], &mxl111sf_table[8],
NULL },
},
{ "Hauppauge 117xxx DVBT (isoc)",
{ NULL },
{ &mxl111sf_table[15], &mxl111sf_table[18],
NULL },
},
{ "Hauppauge 138xxx DVBT (isoc)",
{ NULL },
{ &mxl111sf_table[20], &mxl111sf_table[22],
&mxl111sf_table[24], &mxl111sf_table[26],
NULL },
},
{ "Hauppauge 126xxx (tp-isoc)",
{ NULL },
{ &mxl111sf_table[28], &mxl111sf_table[30],
NULL },
},
}
};
static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
MXL111SF_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
{
.fe_ioctl_override = mxl111sf_fe_ioctl_override,
.num_frontends = 2,
.fe = {{
.size_of_priv = sizeof(struct mxl111sf_adap_state),
.frontend_attach = mxl111sf_lgdt3305_frontend_attach,
.tuner_attach = mxl111sf_attach_tuner,
MXL111SF_EP6_BULK_STREAMING_CONFIG,
},
{
.size_of_priv = sizeof(struct mxl111sf_adap_state),
.frontend_attach = mxl111sf_attach_demod,
.tuner_attach = mxl111sf_attach_tuner,
MXL111SF_EP4_BULK_STREAMING_CONFIG,
}},
},
},
......@@ -776,7 +990,7 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
.adapter = {
{
.fe_ioctl_override = mxl111sf_fe_ioctl_override,
.num_frontends = 1,
.num_frontends = 2,
.fe = {{
.size_of_priv = sizeof(struct mxl111sf_adap_state),
......@@ -784,6 +998,14 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
.tuner_attach = mxl111sf_attach_tuner,
MXL111SF_EP6_ISOC_STREAMING_CONFIG,
},
{
.size_of_priv = sizeof(struct mxl111sf_adap_state),
.frontend_attach = mxl111sf_attach_demod,
.tuner_attach = mxl111sf_attach_tuner,
MXL111SF_EP4_ISOC_STREAMING_CONFIG,
}},
},
},
......
......@@ -133,7 +133,7 @@ extern int dvb_usb_mxl111sf_debug;
/* The following allows the mxl_fail() macro defined below to work
* in externel modules, such as mxl111sf-tuner.ko, even though
* dvb_usb_mxl111sf_debug is not defined within those modules */
#ifdef __MXL111SF_TUNER_H__
#if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__))
#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG
#else
#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug
......
......@@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/dvb/frontends/
ccflags-y += -Idrivers/media/common/tuners/
# For the staging CI driver cxd2099
ccflags-y += -Idrivers/staging/cxd2099/
ccflags-y += -Idrivers/staging/media/cxd2099/
......@@ -128,8 +128,10 @@ struct tea5764_write_regs {
u16 rdsbbl; /* PAUSEDET & RDSBBL */
} __attribute__ ((packed));
#ifndef RADIO_TEA5764_XTAL
#ifdef CONFIG_RADIO_TEA5764_XTAL
#define RADIO_TEA5764_XTAL 1
#else
#define RADIO_TEA5764_XTAL 0
#endif
static int radio_nr = -1;
......
......@@ -517,6 +517,13 @@ config VIDEO_NOON010PC30
source "drivers/media/video/m5mols/Kconfig"
config VIDEO_S5K6AA
tristate "Samsung S5K6AAFX sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
---help---
This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
camera sensor with an embedded SoC image signal processor.
comment "Flash devices"
config VIDEO_ADP1653
......@@ -736,6 +743,8 @@ source "drivers/media/video/cx88/Kconfig"
source "drivers/media/video/cx23885/Kconfig"
source "drivers/media/video/cx25821/Kconfig"
source "drivers/media/video/au0828/Kconfig"
source "drivers/media/video/ivtv/Kconfig"
......
......@@ -72,6 +72,7 @@ obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/
obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o
obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o
......@@ -104,6 +105,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/
obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
obj-$(CONFIG_VIDEO_CX25821) += cx25821/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
......
......@@ -94,6 +94,7 @@ struct atmel_isi {
unsigned int irq;
struct isi_platform_data *pdata;
u16 width_flags; /* max 12 bits */
struct list_head video_buffer_list;
struct frame_buffer *active;
......@@ -248,9 +249,9 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset)
/* ------------------------------------------------------------------
Videobuf operations
------------------------------------------------------------------*/
static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
unsigned int *nplanes, unsigned int sizes[],
void *alloc_ctxs[])
static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
......@@ -647,50 +648,42 @@ static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
fmt->packing == SOC_MBUS_PACKING_EXTEND16);
}
static unsigned long make_bus_param(struct atmel_isi *isi)
{
unsigned long flags;
/*
* Platform specified synchronization and pixel clock polarities are
* only a recommendation and are only used during probing. Atmel ISI
* camera interface only works in master mode, i.e., uses HSYNC and
* VSYNC signals from the sensor
*/
flags = SOCAM_MASTER |
SOCAM_HSYNC_ACTIVE_HIGH |
SOCAM_HSYNC_ACTIVE_LOW |
SOCAM_VSYNC_ACTIVE_HIGH |
SOCAM_VSYNC_ACTIVE_LOW |
SOCAM_PCLK_SAMPLE_RISING |
SOCAM_PCLK_SAMPLE_FALLING |
SOCAM_DATA_ACTIVE_HIGH;
if (isi->pdata->data_width_flags & ISI_DATAWIDTH_10)
flags |= SOCAM_DATAWIDTH_10;
if (isi->pdata->data_width_flags & ISI_DATAWIDTH_8)
flags |= SOCAM_DATAWIDTH_8;
if (flags & SOCAM_DATAWIDTH_MASK)
return flags;
return 0;
}
#define ISI_BUS_PARAM (V4L2_MBUS_MASTER | \
V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
V4L2_MBUS_HSYNC_ACTIVE_LOW | \
V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
V4L2_MBUS_VSYNC_ACTIVE_LOW | \
V4L2_MBUS_PCLK_SAMPLE_RISING | \
V4L2_MBUS_PCLK_SAMPLE_FALLING | \
V4L2_MBUS_DATA_ACTIVE_HIGH)
static int isi_camera_try_bus_param(struct soc_camera_device *icd,
unsigned char buswidth)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct atmel_isi *isi = ici->priv;
unsigned long camera_flags;
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
unsigned long common_flags;
int ret;
camera_flags = icd->ops->query_bus_param(icd);
ret = soc_camera_bus_param_compatible(camera_flags,
make_bus_param(isi));
if (!ret)
return -EINVAL;
return 0;
ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
if (!ret) {
common_flags = soc_mbus_config_compatible(&cfg,
ISI_BUS_PARAM);
if (!common_flags) {
dev_warn(icd->parent,
"Flags incompatible: camera 0x%x, host 0x%x\n",
cfg.flags, ISI_BUS_PARAM);
return -EINVAL;
}
} else if (ret != -ENOIOCTLCMD) {
return ret;
}
if ((1 << (buswidth - 1)) & isi->width_flags)
return 0;
return -EINVAL;
}
......@@ -812,59 +805,71 @@ static int isi_camera_querycap(struct soc_camera_host *ici,
static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct atmel_isi *isi = ici->priv;
unsigned long bus_flags, camera_flags, common_flags;
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
unsigned long common_flags;
int ret;
u32 cfg1 = 0;
camera_flags = icd->ops->query_bus_param(icd);
bus_flags = make_bus_param(isi);
common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
dev_dbg(icd->parent, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n",
camera_flags, bus_flags, common_flags);
if (!common_flags)
return -EINVAL;
ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
if (!ret) {
common_flags = soc_mbus_config_compatible(&cfg,
ISI_BUS_PARAM);
if (!common_flags) {
dev_warn(icd->parent,
"Flags incompatible: camera 0x%x, host 0x%x\n",
cfg.flags, ISI_BUS_PARAM);
return -EINVAL;
}
} else if (ret != -ENOIOCTLCMD) {
return ret;
} else {
common_flags = ISI_BUS_PARAM;
}
dev_dbg(icd->parent, "Flags cam: 0x%x host: 0x%x common: 0x%lx\n",
cfg.flags, ISI_BUS_PARAM, common_flags);
/* Make choises, based on platform preferences */
if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
(common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
(common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
if (isi->pdata->hsync_act_low)
common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
else
common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
}
if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
(common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
(common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
if (isi->pdata->vsync_act_low)
common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
else
common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
}
if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
(common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
(common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
if (isi->pdata->pclk_act_falling)
common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
else
common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
}
ret = icd->ops->set_bus_param(icd, common_flags);
if (ret < 0) {
dev_dbg(icd->parent, "Camera set_bus_param(%lx) returned %d\n",
cfg.flags = common_flags;
ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
if (ret < 0 && ret != -ENOIOCTLCMD) {
dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n",
common_flags, ret);
return ret;
}
/* set bus param for ISI */
if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW;
if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW;
if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING;
if (isi->pdata->has_emb_sync)
......@@ -983,6 +988,11 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev)
goto err_ioremap;
}
if (pdata->data_width_flags & ISI_DATAWIDTH_8)
isi->width_flags = 1 << 7;
if (pdata->data_width_flags & ISI_DATAWIDTH_10)
isi->width_flags |= 1 << 9;
isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
irq = platform_get_irq(pdev, 0);
......
......@@ -1085,6 +1085,8 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
setup.addr = ADDR_UNSET;
setup.type = cx->options.tuner;
setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
if (cx->options.radio > 0)
setup.mode_mask |= T_RADIO;
setup.tuner_callback = (setup.type == TUNER_XC2028) ?
cx18_reset_tuner_gpio : NULL;
cx18_call_all(cx, tuner, s_type_addr, &setup);
......
......@@ -1312,7 +1312,7 @@ int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
return err;
}
if (i > 2) {
if (i >= CX25821_NR_INPUT) {
dprintk(1, "%s(): -EINVAL\n", __func__);
return -EINVAL;
}
......
......@@ -98,6 +98,7 @@
#define CX25821_BOARD_CONEXANT_ATHENA10 1
#define MAX_VID_CHANNEL_NUM 12
#define VID_CHANNEL_NUM 8
#define CX25821_NR_INPUT 2
struct cx25821_fmt {
char *name;
......@@ -196,7 +197,7 @@ struct cx25821_board {
unsigned char radio_addr;
u32 clk_freq;
struct cx25821_input input[2];
struct cx25821_input input[CX25821_NR_INPUT];
};
struct cx25821_subid {
......
......@@ -1923,6 +1923,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2860_BOARD_TERRATEC_AV350 },
{ USB_DEVICE(0x0ccd, 0x0096),
.driver_info = EM2860_BOARD_TERRATEC_GRABBY },
{ USB_DEVICE(0x0ccd, 0x10AF),
.driver_info = EM2860_BOARD_TERRATEC_GRABBY },
{ USB_DEVICE(0x0fd9, 0x0033),
.driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE},
{ USB_DEVICE(0x185b, 0x2870),
......
......@@ -12,11 +12,11 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/v4l2-mediabus.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/soc_camera.h>
#include <media/soc_mediabus.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-chip-ident.h>
......@@ -267,6 +267,17 @@ static int imx074_g_chip_ident(struct v4l2_subdev *sd,
return 0;
}
static int imx074_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
cfg->type = V4L2_MBUS_CSI2;
cfg->flags = V4L2_MBUS_CSI2_2_LANE |
V4L2_MBUS_CSI2_CHANNEL_0 |
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
return 0;
}
static struct v4l2_subdev_video_ops imx074_subdev_video_ops = {
.s_stream = imx074_s_stream,
.s_mbus_fmt = imx074_s_fmt,
......@@ -275,6 +286,7 @@ static struct v4l2_subdev_video_ops imx074_subdev_video_ops = {
.enum_mbus_fmt = imx074_enum_fmt,
.g_crop = imx074_g_crop,
.cropcap = imx074_cropcap,
.g_mbus_config = imx074_g_mbus_config,
};
static struct v4l2_subdev_core_ops imx074_subdev_core_ops = {
......@@ -286,28 +298,7 @@ static struct v4l2_subdev_ops imx074_subdev_ops = {
.video = &imx074_subdev_video_ops,
};
/*
* We have to provide soc-camera operations, but we don't have anything to say
* there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param
*/
static unsigned long imx074_query_bus_param(struct soc_camera_device *icd)
{
return 0;
}
static int imx074_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
return -EINVAL;
}
static struct soc_camera_ops imx074_ops = {
.query_bus_param = imx074_query_bus_param,
.set_bus_param = imx074_set_bus_param,
};
static int imx074_video_probe(struct soc_camera_device *icd,
struct i2c_client *client)
static int imx074_video_probe(struct i2c_client *client)
{
int ret;
u16 id;
......@@ -417,17 +408,10 @@ static int imx074_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct imx074 *priv;
struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct soc_camera_link *icl;
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
int ret;
if (!icd) {
dev_err(&client->dev, "IMX074: missing soc-camera data!\n");
return -EINVAL;
}
icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "IMX074: missing platform data!\n");
return -EINVAL;
......@@ -445,12 +429,10 @@ static int imx074_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops);
icd->ops = &imx074_ops;
priv->fmt = &imx074_colour_fmts[0];
ret = imx074_video_probe(icd, client);
ret = imx074_video_probe(client);
if (ret < 0) {
icd->ops = NULL;
kfree(priv);
return ret;
}
......@@ -461,10 +443,8 @@ static int imx074_probe(struct i2c_client *client,
static int imx074_remove(struct i2c_client *client)
{
struct imx074 *priv = to_imx074(client);
struct soc_camera_device *icd = client->dev.platform_data;
struct soc_camera_link *icl = to_soc_camera_link(icd);
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
icd->ops = NULL;
if (icl->free_bus)
icl->free_bus(icl);
kfree(priv);
......
......@@ -1180,6 +1180,8 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
setup.addr = ADDR_UNSET;
setup.type = itv->options.tuner;
setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
if (itv->options.radio > 0)
setup.mode_mask |= T_RADIO;
setup.tuner_callback = (setup.type == TUNER_XC2028) ?
ivtv_reset_tuner_gpio : NULL;
ivtv_call_all(itv, tuner, s_type_addr, &setup);
......
......@@ -883,7 +883,8 @@ static int mcam_read_setup(struct mcam_camera *cam)
* Videobuf2 interface code.
*/
static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
static int mcam_vb_queue_setup(struct vb2_queue *vq,
const struct v4l2_format *fmt, unsigned int *nbufs,
unsigned int *num_planes, unsigned int sizes[],
void *alloc_ctxs[])
{
......
......@@ -738,9 +738,10 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = {
* Queue operations
*/
static int m2mtest_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
unsigned int *nplanes, unsigned int sizes[],
void *alloc_ctxs[])
static int m2mtest_queue_setup(struct vb2_queue *vq,
const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq);
struct m2mtest_q_data *q_data;
......
......@@ -13,9 +13,11 @@
#include <linux/i2c.h>
#include <linux/log2.h>
#include <media/soc_camera.h>
#include <media/soc_mediabus.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
#include <media/v4l2-ctrls.h>
/*
* mt9m001 i2c address 0x5d
......@@ -84,15 +86,19 @@ static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
struct mt9m001 {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
struct {
/* exposure/auto-exposure cluster */
struct v4l2_ctrl *autoexposure;
struct v4l2_ctrl *exposure;
};
struct v4l2_rect rect; /* Sensor window */
const struct mt9m001_datafmt *fmt;
const struct mt9m001_datafmt *fmts;
int num_fmts;
int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
unsigned int gain;
unsigned int exposure;
unsigned int total_h;
unsigned short y_skip_top; /* Lines to skip at the top */
unsigned char autoexposure;
};
static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
......@@ -165,54 +171,13 @@ static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
static int mt9m001_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK;
/* Only one width bit may be set */
if (!is_power_of_2(width_flag))
return -EINVAL;
if (icl->set_bus_param)
return icl->set_bus_param(icl, width_flag);
/*
* Without board specific bus width settings we only support the
* sensors native bus width
*/
if (width_flag == SOCAM_DATAWIDTH_10)
return 0;
return -EINVAL;
}
static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
{
struct soc_camera_link *icl = to_soc_camera_link(icd);
/* MT9M001 has all capture_format parameters fixed */
unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER;
if (icl->query_bus_param)
flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK;
else
flags |= SOCAM_DATAWIDTH_10;
return soc_camera_apply_sensor_flags(icl, flags);
}
static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct v4l2_rect rect = a->c;
struct soc_camera_device *icd = client->dev.platform_data;
int ret;
const u16 hblank = 9, vblank = 25;
unsigned int total_h;
if (mt9m001->fmts == mt9m001_colour_fmts)
/*
......@@ -231,7 +196,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
soc_camera_limit_side(&rect.top, &rect.height,
MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT);
total_h = rect.height + mt9m001->y_skip_top + vblank;
mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank;
/* Blanking and start values - default... */
ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
......@@ -240,7 +205,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
/*
* The caller provides a supported format, as verified per
* call to icd->try_fmt()
* call to .try_mbus_fmt()
*/
if (!ret)
ret = reg_write(client, MT9M001_COLUMN_START, rect.left);
......@@ -251,17 +216,8 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
if (!ret)
ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
rect.height + mt9m001->y_skip_top - 1);
if (!ret && mt9m001->autoexposure) {
ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h);
if (!ret) {
const struct v4l2_queryctrl *qctrl =
soc_camera_find_qctrl(icd->ops,
V4L2_CID_EXPOSURE);
mt9m001->exposure = (524 + (total_h - 1) *
(qctrl->maximum - qctrl->minimum)) /
1048 + qctrl->minimum;
}
}
if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO)
ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h);
if (!ret)
mt9m001->rect = rect;
......@@ -421,107 +377,48 @@ static int mt9m001_s_register(struct v4l2_subdev *sd,
}
#endif
static const struct v4l2_queryctrl mt9m001_controls[] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Flip Vertically",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
}, {
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
.minimum = 0,
.maximum = 127,
.step = 1,
.default_value = 64,
.flags = V4L2_CTRL_FLAG_SLIDER,
}, {
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Exposure",
.minimum = 1,
.maximum = 255,
.step = 1,
.default_value = 255,
.flags = V4L2_CTRL_FLAG_SLIDER,
}, {
.id = V4L2_CID_EXPOSURE_AUTO,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Automatic Exposure",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1,
}
};
static struct soc_camera_ops mt9m001_ops = {
.set_bus_param = mt9m001_set_bus_param,
.query_bus_param = mt9m001_query_bus_param,
.controls = mt9m001_controls,
.num_controls = ARRAY_SIZE(mt9m001_controls),
};
static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
int data;
struct mt9m001 *mt9m001 = container_of(ctrl->handler,
struct mt9m001, hdl);
s32 min, max;
switch (ctrl->id) {
case V4L2_CID_VFLIP:
data = reg_read(client, MT9M001_READ_OPTIONS2);
if (data < 0)
return -EIO;
ctrl->value = !!(data & 0x8000);
break;
case V4L2_CID_EXPOSURE_AUTO:
ctrl->value = mt9m001->autoexposure;
break;
case V4L2_CID_GAIN:
ctrl->value = mt9m001->gain;
break;
case V4L2_CID_EXPOSURE:
ctrl->value = mt9m001->exposure;
min = mt9m001->exposure->minimum;
max = mt9m001->exposure->maximum;
mt9m001->exposure->val =
(524 + (mt9m001->total_h - 1) * (max - min)) / 1048 + min;
break;
}
return 0;
}
static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct mt9m001 *mt9m001 = container_of(ctrl->handler,
struct mt9m001, hdl);
struct v4l2_subdev *sd = &mt9m001->subdev;
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct soc_camera_device *icd = client->dev.platform_data;
const struct v4l2_queryctrl *qctrl;
struct v4l2_ctrl *exp = mt9m001->exposure;
int data;
qctrl = soc_camera_find_qctrl(&mt9m001_ops, ctrl->id);
if (!qctrl)
return -EINVAL;
switch (ctrl->id) {
case V4L2_CID_VFLIP:
if (ctrl->value)
if (ctrl->val)
data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000);
else
data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000);
if (data < 0)
return -EIO;
break;
return 0;
case V4L2_CID_GAIN:
if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
return -EINVAL;
/* See Datasheet Table 7, Gain settings. */
if (ctrl->value <= qctrl->default_value) {
if (ctrl->val <= ctrl->default_value) {
/* Pack it into 0..1 step 0.125, register values 0..8 */
unsigned long range = qctrl->default_value - qctrl->minimum;
data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
unsigned long range = ctrl->default_value - ctrl->minimum;
data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
dev_dbg(&client->dev, "Setting gain %d\n", data);
data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
......@@ -530,8 +427,8 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
} else {
/* Pack it into 1.125..15 variable step, register values 9..67 */
/* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
unsigned long range = qctrl->maximum - qctrl->default_value - 1;
unsigned long gain = ((ctrl->value - qctrl->default_value - 1) *
unsigned long range = ctrl->maximum - ctrl->default_value - 1;
unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
111 + range / 2) / range + 9;
if (gain <= 32)
......@@ -547,66 +444,44 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
if (data < 0)
return -EIO;
}
return 0;
/* Success */
mt9m001->gain = ctrl->value;
break;
case V4L2_CID_EXPOSURE:
/* mt9m001 has maximum == default */
if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
return -EINVAL;
else {
unsigned long range = qctrl->maximum - qctrl->minimum;
unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 +
case V4L2_CID_EXPOSURE_AUTO:
if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
unsigned long range = exp->maximum - exp->minimum;
unsigned long shutter = ((exp->val - exp->minimum) * 1048 +
range / 2) / range + 1;
dev_dbg(&client->dev,
"Setting shutter width from %d to %lu\n",
reg_read(client, MT9M001_SHUTTER_WIDTH),
shutter);
reg_read(client, MT9M001_SHUTTER_WIDTH), shutter);
if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0)
return -EIO;
mt9m001->exposure = ctrl->value;
mt9m001->autoexposure = 0;
}
break;
case V4L2_CID_EXPOSURE_AUTO:
if (ctrl->value) {
} else {
const u16 vblank = 25;
unsigned int total_h = mt9m001->rect.height +
mt9m001->total_h = mt9m001->rect.height +
mt9m001->y_skip_top + vblank;
if (reg_write(client, MT9M001_SHUTTER_WIDTH,
total_h) < 0)
if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0)
return -EIO;
qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
mt9m001->exposure = (524 + (total_h - 1) *
(qctrl->maximum - qctrl->minimum)) /
1048 + qctrl->minimum;
mt9m001->autoexposure = 1;
} else
mt9m001->autoexposure = 0;
break;
}
return 0;
}
return 0;
return -EINVAL;
}
/*
* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one
*/
static int mt9m001_video_probe(struct soc_camera_device *icd,
static int mt9m001_video_probe(struct soc_camera_link *icl,
struct i2c_client *client)
{
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct soc_camera_link *icl = to_soc_camera_link(icd);
s32 data;
unsigned long flags;
int ret;
/* We must have a parent by now. And it cannot be a wrong one. */
BUG_ON(!icd->parent ||
to_soc_camera_host(icd->parent)->nr != icd->iface);
/* Enable the chip */
data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
dev_dbg(&client->dev, "write: %d\n", data);
......@@ -661,18 +536,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd,
dev_err(&client->dev, "Failed to initialise the camera\n");
/* mt9m001_init() has reset the chip, returning registers to defaults */
mt9m001->gain = 64;
mt9m001->exposure = 255;
return ret;
return v4l2_ctrl_handler_setup(&mt9m001->hdl);
}
static void mt9m001_video_remove(struct soc_camera_device *icd)
static void mt9m001_video_remove(struct soc_camera_link *icl)
{
struct soc_camera_link *icl = to_soc_camera_link(icd);
dev_dbg(icd->pdev, "Video removed: %p, %p\n",
icd->parent, icd->vdev);
if (icl->free_bus)
icl->free_bus(icl);
}
......@@ -687,9 +555,12 @@ static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
return 0;
}
static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = {
.g_volatile_ctrl = mt9m001_g_volatile_ctrl,
.s_ctrl = mt9m001_s_ctrl,
};
static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
.g_ctrl = mt9m001_g_ctrl,
.s_ctrl = mt9m001_s_ctrl,
.g_chip_ident = mt9m001_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9m001_g_register,
......@@ -710,6 +581,40 @@ static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
return 0;
}
static int mt9m001_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
/* MT9M001 has all capture_format parameters fixed */
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER;
cfg->type = V4L2_MBUS_PARALLEL;
cfg->flags = soc_camera_apply_board_flags(icl, cfg);
return 0;
}
static int mt9m001_s_mbus_config(struct v4l2_subdev *sd,
const struct v4l2_mbus_config *cfg)
{
const struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
struct mt9m001 *mt9m001 = to_mt9m001(client);
unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample;
if (icl->set_bus_param)
return icl->set_bus_param(icl, 1 << (bps - 1));
/*
* Without board specific bus width settings we only support the
* sensors native bus width
*/
return bps == 10 ? 0 : -EINVAL;
}
static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
.s_stream = mt9m001_s_stream,
.s_mbus_fmt = mt9m001_s_fmt,
......@@ -719,6 +624,8 @@ static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
.g_crop = mt9m001_g_crop,
.cropcap = mt9m001_cropcap,
.enum_mbus_fmt = mt9m001_enum_fmt,
.g_mbus_config = mt9m001_g_mbus_config,
.s_mbus_config = mt9m001_s_mbus_config,
};
static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = {
......@@ -735,17 +642,10 @@ static int mt9m001_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9m001 *mt9m001;
struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct soc_camera_link *icl;
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
int ret;
if (!icd) {
dev_err(&client->dev, "MT9M001: missing soc-camera data!\n");
return -EINVAL;
}
icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "MT9M001 driver needs platform data\n");
return -EINVAL;
......@@ -762,25 +662,40 @@ static int mt9m001_probe(struct i2c_client *client,
return -ENOMEM;
v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);
v4l2_ctrl_handler_init(&mt9m001->hdl, 4);
v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
V4L2_CID_GAIN, 0, 127, 1, 64);
mt9m001->exposure = v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
V4L2_CID_EXPOSURE, 1, 255, 1, 255);
/*
* Simulated autoexposure. If enabled, we calculate shutter width
* ourselves in the driver based on vertical blanking and frame width
*/
mt9m001->autoexposure = v4l2_ctrl_new_std_menu(&mt9m001->hdl,
&mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
V4L2_EXPOSURE_AUTO);
mt9m001->subdev.ctrl_handler = &mt9m001->hdl;
if (mt9m001->hdl.error) {
int err = mt9m001->hdl.error;
/* Second stage probe - when a capture adapter is there */
icd->ops = &mt9m001_ops;
kfree(mt9m001);
return err;
}
v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure,
V4L2_EXPOSURE_MANUAL, true);
/* Second stage probe - when a capture adapter is there */
mt9m001->y_skip_top = 0;
mt9m001->rect.left = MT9M001_COLUMN_SKIP;
mt9m001->rect.top = MT9M001_ROW_SKIP;
mt9m001->rect.width = MT9M001_MAX_WIDTH;
mt9m001->rect.height = MT9M001_MAX_HEIGHT;
/*
* Simulated autoexposure. If enabled, we calculate shutter width
* ourselves in the driver based on vertical blanking and frame width
*/
mt9m001->autoexposure = 1;
ret = mt9m001_video_probe(icd, client);
ret = mt9m001_video_probe(icl, client);
if (ret) {
icd->ops = NULL;
v4l2_ctrl_handler_free(&mt9m001->hdl);
kfree(mt9m001);
}
......@@ -790,10 +705,11 @@ static int mt9m001_probe(struct i2c_client *client,
static int mt9m001_remove(struct i2c_client *client)
{
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct soc_camera_device *icd = client->dev.platform_data;
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
icd->ops = NULL;
mt9m001_video_remove(icd);
v4l2_device_unregister_subdev(&mt9m001->subdev);
v4l2_ctrl_handler_free(&mt9m001->hdl);
mt9m001_video_remove(icl);
kfree(mt9m001);
return 0;
......
......@@ -13,10 +13,12 @@
#include <linux/log2.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/v4l2-mediabus.h>
#include <media/soc_camera.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
/*
* MT9M111, MT9M112 and MT9M131:
......@@ -177,6 +179,8 @@ enum mt9m111_context {
struct mt9m111 {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
struct v4l2_ctrl *gain;
int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code
* from v4l2-chip-ident.h */
enum mt9m111_context context;
......@@ -185,13 +189,8 @@ struct mt9m111 {
int power_count;
const struct mt9m111_datafmt *fmt;
int lastpage; /* PageMap cache value */
unsigned int gain;
unsigned char autoexposure;
unsigned char datawidth;
unsigned int powered:1;
unsigned int hflip:1;
unsigned int vflip:1;
unsigned int autowhitebalance:1;
};
static struct mt9m111 *to_mt9m111(const struct i2c_client *client)
......@@ -363,21 +362,6 @@ static int mt9m111_reset(struct mt9m111 *mt9m111)
return ret;
}
static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
{
struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
return soc_camera_apply_sensor_flags(icl, flags);
}
static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
{
return 0;
}
static int mt9m111_make_rect(struct mt9m111 *mt9m111,
struct v4l2_rect *rect)
{
......@@ -660,50 +644,6 @@ static int mt9m111_s_register(struct v4l2_subdev *sd,
}
#endif
static const struct v4l2_queryctrl mt9m111_controls[] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Flip Verticaly",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
}, {
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Flip Horizontaly",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
}, { /* gain = 1/32*val (=>gain=1 if val==32) */
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
.minimum = 0,
.maximum = 63 * 2 * 2,
.step = 1,
.default_value = 32,
.flags = V4L2_CTRL_FLAG_SLIDER,
}, {
.id = V4L2_CID_EXPOSURE_AUTO,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Auto Exposure",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1,
}
};
static struct soc_camera_ops mt9m111_ops = {
.query_bus_param = mt9m111_query_bus_param,
.set_bus_param = mt9m111_set_bus_param,
.controls = mt9m111_controls,
.num_controls = ARRAY_SIZE(mt9m111_controls),
};
static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
......@@ -744,7 +684,6 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
if (gain > 63 * 2 * 2)
return -EINVAL;
mt9m111->gain = gain;
if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
val = (1 << 10) | (1 << 9) | (gain / 4);
else if ((gain >= 64) && (gain < 64 * 2))
......@@ -758,118 +697,47 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
int ret;
if (on)
ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
else
ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
if (!ret)
mt9m111->autoexposure = on;
return ret;
return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
}
static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
int ret;
if (on)
ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
else
ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
if (!ret)
mt9m111->autowhitebalance = on;
return ret;
}
static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
int data;
switch (ctrl->id) {
case V4L2_CID_VFLIP:
if (mt9m111->context == HIGHPOWER)
data = reg_read(READ_MODE_B);
else
data = reg_read(READ_MODE_A);
if (data < 0)
return -EIO;
ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS);
break;
case V4L2_CID_HFLIP:
if (mt9m111->context == HIGHPOWER)
data = reg_read(READ_MODE_B);
else
data = reg_read(READ_MODE_A);
if (data < 0)
return -EIO;
ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS);
break;
case V4L2_CID_GAIN:
data = mt9m111_get_global_gain(mt9m111);
if (data < 0)
return data;
ctrl->value = data;
break;
case V4L2_CID_EXPOSURE_AUTO:
ctrl->value = mt9m111->autoexposure;
break;
case V4L2_CID_AUTO_WHITE_BALANCE:
ctrl->value = mt9m111->autowhitebalance;
break;
}
return 0;
return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
}
static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
const struct v4l2_queryctrl *qctrl;
int ret;
qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id);
if (!qctrl)
return -EINVAL;
struct mt9m111 *mt9m111 = container_of(ctrl->handler,
struct mt9m111, hdl);
switch (ctrl->id) {
case V4L2_CID_VFLIP:
mt9m111->vflip = ctrl->value;
ret = mt9m111_set_flip(mt9m111, ctrl->value,
return mt9m111_set_flip(mt9m111, ctrl->val,
MT9M111_RMB_MIRROR_ROWS);
break;
case V4L2_CID_HFLIP:
mt9m111->hflip = ctrl->value;
ret = mt9m111_set_flip(mt9m111, ctrl->value,
return mt9m111_set_flip(mt9m111, ctrl->val,
MT9M111_RMB_MIRROR_COLS);
break;
case V4L2_CID_GAIN:
ret = mt9m111_set_global_gain(mt9m111, ctrl->value);
break;
return mt9m111_set_global_gain(mt9m111, ctrl->val);
case V4L2_CID_EXPOSURE_AUTO:
ret = mt9m111_set_autoexposure(mt9m111, ctrl->value);
break;
return mt9m111_set_autoexposure(mt9m111, ctrl->val);
case V4L2_CID_AUTO_WHITE_BALANCE:
ret = mt9m111_set_autowhitebalance(mt9m111, ctrl->value);
break;
default:
ret = -EINVAL;
return mt9m111_set_autowhitebalance(mt9m111, ctrl->val);
}
return ret;
return -EINVAL;
}
static int mt9m111_suspend(struct mt9m111 *mt9m111)
{
mt9m111->gain = mt9m111_get_global_gain(mt9m111);
v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111));
return 0;
}
......@@ -879,11 +747,7 @@ static void mt9m111_restore_state(struct mt9m111 *mt9m111)
mt9m111_set_context(mt9m111, mt9m111->context);
mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
mt9m111_setup_rect(mt9m111, &mt9m111->rect);
mt9m111_set_flip(mt9m111, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
mt9m111_set_flip(mt9m111, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
mt9m111_set_global_gain(mt9m111, mt9m111->gain);
mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure);
mt9m111_set_autowhitebalance(mt9m111, mt9m111->autowhitebalance);
v4l2_ctrl_handler_setup(&mt9m111->hdl);
}
static int mt9m111_resume(struct mt9m111 *mt9m111)
......@@ -911,8 +775,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111)
ret = mt9m111_reset(mt9m111);
if (!ret)
ret = mt9m111_set_context(mt9m111, mt9m111->context);
if (!ret)
ret = mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure);
if (ret)
dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
return ret;
......@@ -922,22 +784,12 @@ static int mt9m111_init(struct mt9m111 *mt9m111)
* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one
*/
static int mt9m111_video_probe(struct soc_camera_device *icd,
struct i2c_client *client)
static int mt9m111_video_probe(struct i2c_client *client)
{
struct mt9m111 *mt9m111 = to_mt9m111(client);
s32 data;
int ret;
/* We must have a parent by now. And it cannot be a wrong one. */
BUG_ON(!icd->parent ||
to_soc_camera_host(icd->parent)->nr != icd->iface);
mt9m111->lastpage = -1;
mt9m111->autoexposure = 1;
mt9m111->autowhitebalance = 1;
data = reg_read(CHIP_VERSION);
switch (data) {
......@@ -951,17 +803,16 @@ static int mt9m111_video_probe(struct soc_camera_device *icd,
dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
break;
default:
ret = -ENODEV;
dev_err(&client->dev,
"No MT9M111/MT9M112/MT9M131 chip detected register read %x\n",
data);
goto ei2c;
return -ENODEV;
}
ret = mt9m111_init(mt9m111);
ei2c:
return ret;
if (ret)
return ret;
return v4l2_ctrl_handler_setup(&mt9m111->hdl);
}
static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
......@@ -998,9 +849,11 @@ static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
return ret;
}
static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
.s_ctrl = mt9m111_s_ctrl,
};
static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
.g_ctrl = mt9m111_g_ctrl,
.s_ctrl = mt9m111_s_ctrl,
.g_chip_ident = mt9m111_g_chip_ident,
.s_power = mt9m111_s_power,
#ifdef CONFIG_VIDEO_ADV_DEBUG
......@@ -1019,6 +872,21 @@ static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
return 0;
}
static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
cfg->flags = soc_camera_apply_board_flags(icl, cfg);
return 0;
}
static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
.s_mbus_fmt = mt9m111_s_fmt,
.g_mbus_fmt = mt9m111_g_fmt,
......@@ -1027,6 +895,7 @@ static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
.g_crop = mt9m111_g_crop,
.cropcap = mt9m111_cropcap,
.enum_mbus_fmt = mt9m111_enum_fmt,
.g_mbus_config = mt9m111_g_mbus_config,
};
static struct v4l2_subdev_ops mt9m111_subdev_ops = {
......@@ -1038,17 +907,10 @@ static int mt9m111_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9m111 *mt9m111;
struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct soc_camera_link *icl;
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
int ret;
if (!icd) {
dev_err(&client->dev, "mt9m111: soc-camera data missing!\n");
return -EINVAL;
}
icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "mt9m111: driver needs platform data\n");
return -EINVAL;
......@@ -1065,19 +927,37 @@ static int mt9m111_probe(struct i2c_client *client,
return -ENOMEM;
v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
v4l2_ctrl_handler_init(&mt9m111->hdl, 5);
v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
mt9m111->gain = v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
V4L2_CID_GAIN, 0, 63 * 2 * 2, 1, 32);
v4l2_ctrl_new_std_menu(&mt9m111->hdl,
&mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
V4L2_EXPOSURE_AUTO);
mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
if (mt9m111->hdl.error) {
int err = mt9m111->hdl.error;
/* Second stage probe - when a capture adapter is there */
icd->ops = &mt9m111_ops;
kfree(mt9m111);
return err;
}
/* Second stage probe - when a capture adapter is there */
mt9m111->rect.left = MT9M111_MIN_DARK_COLS;
mt9m111->rect.top = MT9M111_MIN_DARK_ROWS;
mt9m111->rect.width = MT9M111_MAX_WIDTH;
mt9m111->rect.height = MT9M111_MAX_HEIGHT;
mt9m111->fmt = &mt9m111_colour_fmts[0];
mt9m111->lastpage = -1;
ret = mt9m111_video_probe(icd, client);
ret = mt9m111_video_probe(client);
if (ret) {
icd->ops = NULL;
v4l2_ctrl_handler_free(&mt9m111->hdl);
kfree(mt9m111);
}
......@@ -1087,9 +967,9 @@ static int mt9m111_probe(struct i2c_client *client,
static int mt9m111_remove(struct i2c_client *client)
{
struct mt9m111 *mt9m111 = to_mt9m111(client);
struct soc_camera_device *icd = client->dev.platform_data;
icd->ops = NULL;
v4l2_device_unregister_subdev(&mt9m111->subdev);
v4l2_ctrl_handler_free(&mt9m111->hdl);
kfree(mt9m111);
return 0;
......
......@@ -13,11 +13,20 @@
#include <linux/log2.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/v4l2-mediabus.h>
#include <linux/videodev2.h>
#include <media/soc_camera.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
/*
* ATTENTION: this driver still cannot be used outside of the soc-camera
* framework because of its PM implementation, using the video_device node.
* If hardware becomes available for testing, alternative PM approaches shall
* be considered and tested.
*/
/*
* mt9t031 i2c address 0x5d
......@@ -57,21 +66,20 @@
#define MT9T031_COLUMN_SKIP 32
#define MT9T031_ROW_SKIP 20
#define MT9T031_BUS_PARAM (SOCAM_PCLK_SAMPLE_RISING | \
SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH | \
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \
SOCAM_MASTER | SOCAM_DATAWIDTH_10)
struct mt9t031 {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
struct {
/* exposure/auto-exposure cluster */
struct v4l2_ctrl *autoexposure;
struct v4l2_ctrl *exposure;
};
struct v4l2_rect rect; /* Sensor window */
int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
u16 xskip;
u16 yskip;
unsigned int gain;
unsigned int total_h;
unsigned short y_skip_top; /* Lines to skip at the top */
unsigned int exposure;
unsigned char autoexposure;
};
static struct mt9t031 *to_mt9t031(const struct i2c_client *client)
......@@ -179,95 +187,6 @@ static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
static int mt9t031_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
/* The caller should have queried our parameters, check anyway */
if (flags & ~MT9T031_BUS_PARAM)
return -EINVAL;
if (flags & SOCAM_PCLK_SAMPLE_FALLING)
reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
else
reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
return 0;
}
static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
{
struct soc_camera_link *icl = to_soc_camera_link(icd);
return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM);
}
enum {
MT9T031_CTRL_VFLIP,
MT9T031_CTRL_HFLIP,
MT9T031_CTRL_GAIN,
MT9T031_CTRL_EXPOSURE,
MT9T031_CTRL_EXPOSURE_AUTO,
};
static const struct v4l2_queryctrl mt9t031_controls[] = {
[MT9T031_CTRL_VFLIP] = {
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Flip Vertically",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
[MT9T031_CTRL_HFLIP] = {
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Flip Horizontally",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
[MT9T031_CTRL_GAIN] = {
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
.minimum = 0,
.maximum = 127,
.step = 1,
.default_value = 64,
.flags = V4L2_CTRL_FLAG_SLIDER,
},
[MT9T031_CTRL_EXPOSURE] = {
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Exposure",
.minimum = 1,
.maximum = 255,
.step = 1,
.default_value = 255,
.flags = V4L2_CTRL_FLAG_SLIDER,
},
[MT9T031_CTRL_EXPOSURE_AUTO] = {
.id = V4L2_CID_EXPOSURE_AUTO,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Automatic Exposure",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1,
}
};
static struct soc_camera_ops mt9t031_ops = {
.set_bus_param = mt9t031_set_bus_param,
.query_bus_param = mt9t031_query_bus_param,
.controls = mt9t031_controls,
.num_controls = ARRAY_SIZE(mt9t031_controls),
};
/* target must be _even_ */
static u16 mt9t031_skip(s32 *source, s32 target, s32 max)
{
......@@ -353,7 +272,7 @@ static int mt9t031_set_params(struct i2c_client *client,
/*
* The caller provides a supported format, as guaranteed by
* icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap()
* .try_mbus_fmt(), soc_camera_s_crop() and soc_camera_cropcap()
*/
if (ret >= 0)
ret = reg_write(client, MT9T031_COLUMN_START, rect->left);
......@@ -364,17 +283,10 @@ static int mt9t031_set_params(struct i2c_client *client,
if (ret >= 0)
ret = reg_write(client, MT9T031_WINDOW_HEIGHT,
rect->height + mt9t031->y_skip_top - 1);
if (ret >= 0 && mt9t031->autoexposure) {
unsigned int total_h = rect->height + mt9t031->y_skip_top + vblank;
ret = set_shutter(client, total_h);
if (ret >= 0) {
const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
const struct v4l2_queryctrl *qctrl =
&mt9t031_controls[MT9T031_CTRL_EXPOSURE];
mt9t031->exposure = (shutter_max / 2 + (total_h - 1) *
(qctrl->maximum - qctrl->minimum)) /
shutter_max + qctrl->minimum;
}
if (ret >= 0 && v4l2_ctrl_g_ctrl(mt9t031->autoexposure) == V4L2_EXPOSURE_AUTO) {
mt9t031->total_h = rect->height + mt9t031->y_skip_top + vblank;
ret = set_shutter(client, mt9t031->total_h);
}
/* Re-enable register update, commit all changes */
......@@ -543,71 +455,57 @@ static int mt9t031_s_register(struct v4l2_subdev *sd,
}
#endif
static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int mt9t031_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
int data;
struct mt9t031 *mt9t031 = container_of(ctrl->handler,
struct mt9t031, hdl);
const u32 shutter_max = MT9T031_MAX_HEIGHT + MT9T031_VERTICAL_BLANK;
s32 min, max;
switch (ctrl->id) {
case V4L2_CID_VFLIP:
data = reg_read(client, MT9T031_READ_MODE_2);
if (data < 0)
return -EIO;
ctrl->value = !!(data & 0x8000);
break;
case V4L2_CID_HFLIP:
data = reg_read(client, MT9T031_READ_MODE_2);
if (data < 0)
return -EIO;
ctrl->value = !!(data & 0x4000);
break;
case V4L2_CID_EXPOSURE_AUTO:
ctrl->value = mt9t031->autoexposure;
break;
case V4L2_CID_GAIN:
ctrl->value = mt9t031->gain;
break;
case V4L2_CID_EXPOSURE:
ctrl->value = mt9t031->exposure;
min = mt9t031->exposure->minimum;
max = mt9t031->exposure->maximum;
mt9t031->exposure->val =
(shutter_max / 2 + (mt9t031->total_h - 1) * (max - min))
/ shutter_max + min;
break;
}
return 0;
}
static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct mt9t031 *mt9t031 = container_of(ctrl->handler,
struct mt9t031, hdl);
struct v4l2_subdev *sd = &mt9t031->subdev;
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
const struct v4l2_queryctrl *qctrl;
struct v4l2_ctrl *exp = mt9t031->exposure;
int data;
switch (ctrl->id) {
case V4L2_CID_VFLIP:
if (ctrl->value)
if (ctrl->val)
data = reg_set(client, MT9T031_READ_MODE_2, 0x8000);
else
data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000);
if (data < 0)
return -EIO;
break;
return 0;
case V4L2_CID_HFLIP:
if (ctrl->value)
if (ctrl->val)
data = reg_set(client, MT9T031_READ_MODE_2, 0x4000);
else
data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000);
if (data < 0)
return -EIO;
break;
return 0;
case V4L2_CID_GAIN:
qctrl = &mt9t031_controls[MT9T031_CTRL_GAIN];
if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
return -EINVAL;
/* See Datasheet Table 7, Gain settings. */
if (ctrl->value <= qctrl->default_value) {
if (ctrl->val <= ctrl->default_value) {
/* Pack it into 0..1 step 0.125, register values 0..8 */
unsigned long range = qctrl->default_value - qctrl->minimum;
data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
unsigned long range = ctrl->default_value - ctrl->minimum;
data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
dev_dbg(&client->dev, "Setting gain %d\n", data);
data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
......@@ -616,9 +514,9 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
} else {
/* Pack it into 1.125..128 variable step, register values 9..0x7860 */
/* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
unsigned long range = qctrl->maximum - qctrl->default_value - 1;
unsigned long range = ctrl->maximum - ctrl->default_value - 1;
/* calculated gain: map 65..127 to 9..1024 step 0.125 */
unsigned long gain = ((ctrl->value - qctrl->default_value - 1) *
unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
1015 + range / 2) / range + 9;
if (gain <= 32) /* calculated gain 9..32 -> 9..32 */
......@@ -635,19 +533,13 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
if (data < 0)
return -EIO;
}
return 0;
/* Success */
mt9t031->gain = ctrl->value;
break;
case V4L2_CID_EXPOSURE:
qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE];
/* mt9t031 has maximum == default */
if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
return -EINVAL;
else {
const unsigned long range = qctrl->maximum - qctrl->minimum;
const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 +
range / 2) / range + 1;
case V4L2_CID_EXPOSURE_AUTO:
if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
unsigned int range = exp->maximum - exp->minimum;
unsigned int shutter = ((exp->val - exp->minimum) * 1048 +
range / 2) / range + 1;
u32 old;
get_shutter(client, &old);
......@@ -655,27 +547,15 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
old, shutter);
if (set_shutter(client, shutter) < 0)
return -EIO;
mt9t031->exposure = ctrl->value;
mt9t031->autoexposure = 0;
}
break;
case V4L2_CID_EXPOSURE_AUTO:
if (ctrl->value) {
} else {
const u16 vblank = MT9T031_VERTICAL_BLANK;
const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
unsigned int total_h = mt9t031->rect.height +
mt9t031->total_h = mt9t031->rect.height +
mt9t031->y_skip_top + vblank;
if (set_shutter(client, total_h) < 0)
if (set_shutter(client, mt9t031->total_h) < 0)
return -EIO;
qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE];
mt9t031->exposure = (shutter_max / 2 + (total_h - 1) *
(qctrl->maximum - qctrl->minimum)) /
shutter_max + qctrl->minimum;
mt9t031->autoexposure = 1;
} else
mt9t031->autoexposure = 0;
break;
}
return 0;
default:
return -EINVAL;
}
......@@ -700,8 +580,7 @@ static int mt9t031_runtime_suspend(struct device *dev)
static int mt9t031_runtime_resume(struct device *dev)
{
struct video_device *vdev = to_video_device(dev);
struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct v4l2_subdev *sd = soc_camera_vdev_to_subdev(vdev);
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
......@@ -734,6 +613,19 @@ static struct device_type mt9t031_dev_type = {
.pm = &mt9t031_dev_pm_ops,
};
static int mt9t031_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct video_device *vdev = soc_camera_i2c_to_vdev(client);
if (on)
vdev->dev.type = &mt9t031_dev_type;
else
vdev->dev.type = NULL;
return 0;
}
/*
* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one
......@@ -741,7 +633,6 @@ static struct device_type mt9t031_dev_type = {
static int mt9t031_video_probe(struct i2c_client *client)
{
struct mt9t031 *mt9t031 = to_mt9t031(client);
struct video_device *vdev = soc_camera_i2c_to_vdev(client);
s32 data;
int ret;
......@@ -768,11 +659,7 @@ static int mt9t031_video_probe(struct i2c_client *client)
if (ret < 0)
dev_err(&client->dev, "Failed to initialise the camera\n");
else
vdev->dev.type = &mt9t031_dev_type;
/* mt9t031_idle() has reset the chip to default. */
mt9t031->exposure = 255;
mt9t031->gain = 64;
v4l2_ctrl_handler_setup(&mt9t031->hdl);
return ret;
}
......@@ -787,10 +674,14 @@ static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
return 0;
}
static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = {
.g_volatile_ctrl = mt9t031_g_volatile_ctrl,
.s_ctrl = mt9t031_s_ctrl,
};
static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
.g_ctrl = mt9t031_g_ctrl,
.s_ctrl = mt9t031_s_ctrl,
.g_chip_ident = mt9t031_g_chip_ident,
.s_power = mt9t031_s_power,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9t031_g_register,
.s_register = mt9t031_s_register,
......@@ -807,6 +698,34 @@ static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
return 0;
}
static int mt9t031_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
cfg->flags = soc_camera_apply_board_flags(icl, cfg);
return 0;
}
static int mt9t031_s_mbus_config(struct v4l2_subdev *sd,
const struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
if (soc_camera_apply_board_flags(icl, cfg) &
V4L2_MBUS_PCLK_SAMPLE_FALLING)
return reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
else
return reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
}
static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = {
.s_stream = mt9t031_s_stream,
.s_mbus_fmt = mt9t031_s_fmt,
......@@ -816,6 +735,8 @@ static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = {
.g_crop = mt9t031_g_crop,
.cropcap = mt9t031_cropcap,
.enum_mbus_fmt = mt9t031_enum_fmt,
.g_mbus_config = mt9t031_g_mbus_config,
.s_mbus_config = mt9t031_s_mbus_config,
};
static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = {
......@@ -832,18 +753,13 @@ static int mt9t031_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9t031 *mt9t031;
struct soc_camera_device *icd = client->dev.platform_data;
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int ret;
if (icd) {
struct soc_camera_link *icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "MT9T031 driver needs platform data\n");
return -EINVAL;
}
icd->ops = &mt9t031_ops;
if (!icl) {
dev_err(&client->dev, "MT9T031 driver needs platform data\n");
return -EINVAL;
}
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
......@@ -857,6 +773,33 @@ static int mt9t031_probe(struct i2c_client *client,
return -ENOMEM;
v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops);
v4l2_ctrl_handler_init(&mt9t031->hdl, 5);
v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
V4L2_CID_GAIN, 0, 127, 1, 64);
/*
* Simulated autoexposure. If enabled, we calculate shutter width
* ourselves in the driver based on vertical blanking and frame width
*/
mt9t031->autoexposure = v4l2_ctrl_new_std_menu(&mt9t031->hdl,
&mt9t031_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
V4L2_EXPOSURE_AUTO);
mt9t031->exposure = v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
V4L2_CID_EXPOSURE, 1, 255, 1, 255);
mt9t031->subdev.ctrl_handler = &mt9t031->hdl;
if (mt9t031->hdl.error) {
int err = mt9t031->hdl.error;
kfree(mt9t031);
return err;
}
v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure,
V4L2_EXPOSURE_MANUAL, true);
mt9t031->y_skip_top = 0;
mt9t031->rect.left = MT9T031_COLUMN_SKIP;
......@@ -864,12 +807,6 @@ static int mt9t031_probe(struct i2c_client *client,
mt9t031->rect.width = MT9T031_MAX_WIDTH;
mt9t031->rect.height = MT9T031_MAX_HEIGHT;
/*
* Simulated autoexposure. If enabled, we calculate shutter width
* ourselves in the driver based on vertical blanking and frame width
*/
mt9t031->autoexposure = 1;
mt9t031->xskip = 1;
mt9t031->yskip = 1;
......@@ -880,8 +817,7 @@ static int mt9t031_probe(struct i2c_client *client,
mt9t031_disable(client);
if (ret) {
if (icd)
icd->ops = NULL;
v4l2_ctrl_handler_free(&mt9t031->hdl);
kfree(mt9t031);
}
......@@ -891,10 +827,9 @@ static int mt9t031_probe(struct i2c_client *client,
static int mt9t031_remove(struct i2c_client *client)
{
struct mt9t031 *mt9t031 = to_mt9t031(client);
struct soc_camera_device *icd = client->dev.platform_data;
if (icd)
icd->ops = NULL;
v4l2_device_unregister_subdev(&mt9t031->subdev);
v4l2_ctrl_handler_free(&mt9t031->hdl);
kfree(mt9t031);
return 0;
......
......@@ -22,11 +22,11 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/v4l2-mediabus.h>
#include <linux/videodev2.h>
#include <media/mt9t112.h>
#include <media/soc_camera.h>
#include <media/soc_mediabus.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-common.h>
......@@ -34,11 +34,7 @@
/* #define EXT_CLOCK 24000000 */
/************************************************************************
macro
************************************************************************/
/*
* frame size
......@@ -80,17 +76,8 @@
#define VAR8(id, offset) _VAR(id, offset, 0x8000)
/************************************************************************
struct
************************************************************************/
struct mt9t112_frame_size {
u16 width;
u16 height;
};
struct mt9t112_format {
enum v4l2_mbus_pixelcode code;
enum v4l2_colorspace colorspace;
......@@ -102,21 +89,17 @@ struct mt9t112_priv {
struct v4l2_subdev subdev;
struct mt9t112_camera_info *info;
struct i2c_client *client;
struct soc_camera_device icd;
struct mt9t112_frame_size frame;
struct v4l2_rect frame;
const struct mt9t112_format *format;
int model;
u32 flags;
/* for flags */
#define INIT_DONE (1<<0)
#define INIT_DONE (1 << 0)
#define PCLK_RISING (1 << 1)
};
/************************************************************************
supported format
************************************************************************/
static const struct mt9t112_format mt9t112_cfmts[] = {
......@@ -154,11 +137,7 @@ static const struct mt9t112_format mt9t112_cfmts[] = {
};
/************************************************************************
general function
************************************************************************/
static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client)
{
......@@ -326,50 +305,47 @@ static int mt9t112_clock_info(const struct i2c_client *client, u32 ext)
n = (n >> 8) & 0x003f;
enable = ((6000 > ext) || (54000 < ext)) ? "X" : "";
dev_info(&client->dev, "EXTCLK : %10u K %s\n", ext, enable);
dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable);
vco = 2 * m * ext / (n+1);
enable = ((384000 > vco) || (768000 < vco)) ? "X" : "";
dev_info(&client->dev, "VCO : %10u K %s\n", vco, enable);
dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable);
clk = vco / (p1+1) / (p2+1);
enable = (96000 < clk) ? "X" : "";
dev_info(&client->dev, "PIXCLK : %10u K %s\n", clk, enable);
dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable);
clk = vco / (p3+1);
enable = (768000 < clk) ? "X" : "";
dev_info(&client->dev, "MIPICLK : %10u K %s\n", clk, enable);
dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable);
clk = vco / (p6+1);
enable = (96000 < clk) ? "X" : "";
dev_info(&client->dev, "MCU CLK : %10u K %s\n", clk, enable);
dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable);
clk = vco / (p5+1);
enable = (54000 < clk) ? "X" : "";
dev_info(&client->dev, "SOC CLK : %10u K %s\n", clk, enable);
dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable);
clk = vco / (p4+1);
enable = (70000 < clk) ? "X" : "";
dev_info(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable);
dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable);
clk = vco / (p7+1);
dev_info(&client->dev, "External sensor : %10u K\n", clk);
dev_dbg(&client->dev, "External sensor : %10u K\n", clk);
clk = ext / (n+1);
enable = ((2000 > clk) || (24000 < clk)) ? "X" : "";
dev_info(&client->dev, "PFD : %10u K %s\n", clk, enable);
dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable);
return 0;
}
#endif
static void mt9t112_frame_check(u32 *width, u32 *height)
static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top)
{
if (*width > MAX_WIDTH)
*width = MAX_WIDTH;
if (*height > MAX_HEIGHT)
*height = MAX_HEIGHT;
soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH);
soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT);
}
static int mt9t112_set_a_frame_size(const struct i2c_client *client,
......@@ -758,48 +734,7 @@ static int mt9t112_init_camera(const struct i2c_client *client)
}
/************************************************************************
soc_camera_ops
************************************************************************/
static int mt9t112_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
return 0;
}
static unsigned long mt9t112_query_bus_param(struct soc_camera_device *icd)
{
struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
struct mt9t112_priv *priv = to_mt9t112(client);
struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned long flags = SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH;
flags |= (priv->info->flags & MT9T112_FLAG_PCLK_RISING_EDGE) ?
SOCAM_PCLK_SAMPLE_RISING : SOCAM_PCLK_SAMPLE_FALLING;
if (priv->info->flags & MT9T112_FLAG_DATAWIDTH_8)
flags |= SOCAM_DATAWIDTH_8;
else
flags |= SOCAM_DATAWIDTH_10;
return soc_camera_apply_sensor_flags(icl, flags);
}
static struct soc_camera_ops mt9t112_ops = {
.set_bus_param = mt9t112_set_bus_param,
.query_bus_param = mt9t112_query_bus_param,
};
/************************************************************************
v4l2_subdev_core_ops
************************************************************************/
static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
......@@ -850,11 +785,7 @@ static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
/************************************************************************
v4l2_subdev_video_ops
************************************************************************/
static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
{
......@@ -877,8 +808,7 @@ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
}
if (!(priv->flags & INIT_DONE)) {
u16 param = (MT9T112_FLAG_PCLK_RISING_EDGE &
priv->info->flags) ? 0x0001 : 0x0000;
u16 param = PCLK_RISING & priv->flags ? 0x0001 : 0x0000;
ECHECKER(ret, mt9t112_init_camera(client));
......@@ -910,19 +840,12 @@ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
return ret;
}
static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height,
static int mt9t112_set_params(struct mt9t112_priv *priv,
const struct v4l2_rect *rect,
enum v4l2_mbus_pixelcode code)
{
struct mt9t112_priv *priv = to_mt9t112(client);
int i;
priv->format = NULL;
/*
* frame size check
*/
mt9t112_frame_check(&width, &height);
/*
* get color format
*/
......@@ -933,8 +856,13 @@ static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height,
if (i == ARRAY_SIZE(mt9t112_cfmts))
return -EINVAL;
priv->frame.width = (u16)width;
priv->frame.height = (u16)height;
priv->frame = *rect;
/*
* frame size check
*/
mt9t112_frame_check(&priv->frame.width, &priv->frame.height,
&priv->frame.left, &priv->frame.top);
priv->format = mt9t112_cfmts + i;
......@@ -945,9 +873,12 @@ static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{
a->bounds.left = 0;
a->bounds.top = 0;
a->bounds.width = VGA_WIDTH;
a->bounds.height = VGA_HEIGHT;
a->defrect = a->bounds;
a->bounds.width = MAX_WIDTH;
a->bounds.height = MAX_HEIGHT;
a->defrect.left = 0;
a->defrect.top = 0;
a->defrect.width = VGA_WIDTH;
a->defrect.height = VGA_HEIGHT;
a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
a->pixelaspect.numerator = 1;
a->pixelaspect.denominator = 1;
......@@ -957,11 +888,11 @@ static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
a->c.left = 0;
a->c.top = 0;
a->c.width = VGA_WIDTH;
a->c.height = VGA_HEIGHT;
a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t112_priv *priv = to_mt9t112(client);
a->c = priv->frame;
a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
return 0;
}
......@@ -969,10 +900,10 @@ static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t112_priv *priv = to_mt9t112(client);
struct v4l2_rect *rect = &a->c;
return mt9t112_set_params(client, rect->width, rect->height,
V4L2_MBUS_FMT_UYVY8_2X8);
return mt9t112_set_params(priv, rect, priv->format->code);
}
static int mt9t112_g_fmt(struct v4l2_subdev *sd,
......@@ -981,16 +912,9 @@ static int mt9t112_g_fmt(struct v4l2_subdev *sd,
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t112_priv *priv = to_mt9t112(client);
if (!priv->format) {
int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT,
V4L2_MBUS_FMT_UYVY8_2X8);
if (ret < 0)
return ret;
}
mf->width = priv->frame.width;
mf->height = priv->frame.height;
/* TODO: set colorspace */
mf->colorspace = priv->format->colorspace;
mf->code = priv->format->code;
mf->field = V4L2_FIELD_NONE;
......@@ -1001,17 +925,42 @@ static int mt9t112_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t112_priv *priv = to_mt9t112(client);
struct v4l2_rect rect = {
.width = mf->width,
.height = mf->height,
.left = priv->frame.left,
.top = priv->frame.top,
};
int ret;
ret = mt9t112_set_params(priv, &rect, mf->code);
if (!ret)
mf->colorspace = priv->format->colorspace;
/* TODO: set colorspace */
return mt9t112_set_params(client, mf->width, mf->height, mf->code);
return ret;
}
static int mt9t112_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
mt9t112_frame_check(&mf->width, &mf->height);
unsigned int top, left;
int i;
for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++)
if (mt9t112_cfmts[i].code == mf->code)
break;
if (i == ARRAY_SIZE(mt9t112_cfmts)) {
mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_JPEG;
} else {
mf->colorspace = mt9t112_cfmts[i].colorspace;
}
mt9t112_frame_check(&mf->width, &mf->height, &left, &top);
/* TODO: set colorspace */
mf->field = V4L2_FIELD_NONE;
return 0;
......@@ -1024,6 +973,35 @@ static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
return -EINVAL;
*code = mt9t112_cfmts[index].code;
return 0;
}
static int mt9t112_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH |
V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING;
cfg->type = V4L2_MBUS_PARALLEL;
cfg->flags = soc_camera_apply_board_flags(icl, cfg);
return 0;
}
static int mt9t112_s_mbus_config(struct v4l2_subdev *sd,
const struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
struct mt9t112_priv *priv = to_mt9t112(client);
if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING)
priv->flags |= PCLK_RISING;
return 0;
}
......@@ -1036,31 +1014,24 @@ static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = {
.g_crop = mt9t112_g_crop,
.s_crop = mt9t112_s_crop,
.enum_mbus_fmt = mt9t112_enum_fmt,
.g_mbus_config = mt9t112_g_mbus_config,
.s_mbus_config = mt9t112_s_mbus_config,
};
/************************************************************************
i2c driver
************************************************************************/
static struct v4l2_subdev_ops mt9t112_subdev_ops = {
.core = &mt9t112_subdev_core_ops,
.video = &mt9t112_subdev_video_ops,
};
static int mt9t112_camera_probe(struct soc_camera_device *icd,
struct i2c_client *client)
static int mt9t112_camera_probe(struct i2c_client *client)
{
struct mt9t112_priv *priv = to_mt9t112(client);
const char *devname;
int chipid;
/* We must have a parent by now. And it cannot be a wrong one. */
BUG_ON(!icd->parent ||
to_soc_camera_host(icd->parent)->nr != icd->iface);
/*
* check and show chip ID
*/
......@@ -1088,20 +1059,21 @@ static int mt9t112_camera_probe(struct soc_camera_device *icd,
static int mt9t112_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9t112_priv *priv;
struct soc_camera_device *icd = client->dev.platform_data;
struct soc_camera_link *icl;
int ret;
struct mt9t112_priv *priv;
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
struct v4l2_rect rect = {
.width = VGA_WIDTH,
.height = VGA_HEIGHT,
.left = (MAX_WIDTH - VGA_WIDTH) / 2,
.top = (MAX_HEIGHT - VGA_HEIGHT) / 2,
};
int ret;
if (!icd) {
dev_err(&client->dev, "mt9t112: missing soc-camera data!\n");
if (!icl || !icl->priv) {
dev_err(&client->dev, "mt9t112: missing platform data!\n");
return -EINVAL;
}
icl = to_soc_camera_link(icd);
if (!icl || !icl->priv)
return -EINVAL;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
......@@ -1110,13 +1082,12 @@ static int mt9t112_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
icd->ops = &mt9t112_ops;
ret = mt9t112_camera_probe(icd, client);
if (ret) {
icd->ops = NULL;
ret = mt9t112_camera_probe(client);
if (ret)
kfree(priv);
}
/* Cannot fail: using the default supported pixel code */
mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
return ret;
}
......@@ -1124,9 +1095,7 @@ static int mt9t112_probe(struct i2c_client *client,
static int mt9t112_remove(struct i2c_client *client)
{
struct mt9t112_priv *priv = to_mt9t112(client);
struct soc_camera_device *icd = client->dev.platform_data;
icd->ops = NULL;
kfree(priv);
return 0;
}
......@@ -1147,11 +1116,7 @@ static struct i2c_driver mt9t112_i2c_driver = {
};
/************************************************************************
module function
************************************************************************/
static int __init mt9t112_module_init(void)
{
......
......@@ -14,9 +14,11 @@
#include <linux/delay.h>
#include <linux/log2.h>
#include <media/soc_camera.h>
#include <media/soc_mediabus.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
#include <media/v4l2-ctrls.h>
/*
* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
......@@ -100,6 +102,17 @@ static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
struct mt9v022 {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
struct {
/* exposure/auto-exposure cluster */
struct v4l2_ctrl *autoexposure;
struct v4l2_ctrl *exposure;
};
struct {
/* gain/auto-gain cluster */
struct v4l2_ctrl *autogain;
struct v4l2_ctrl *gain;
};
struct v4l2_rect rect; /* Sensor window */
const struct mt9v022_datafmt *fmt;
const struct mt9v022_datafmt *fmts;
......@@ -178,6 +191,8 @@ static int mt9v022_init(struct i2c_client *client)
ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
if (!ret)
ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0);
if (!ret)
return v4l2_ctrl_handler_setup(&mt9v022->hdl);
return ret;
}
......@@ -199,78 +214,6 @@ static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
static int mt9v022_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
int ret;
u16 pixclk = 0;
/* Only one width bit may be set */
if (!is_power_of_2(width_flag))
return -EINVAL;
if (icl->set_bus_param) {
ret = icl->set_bus_param(icl, width_flag);
if (ret)
return ret;
} else {
/*
* Without board specific bus width settings we only support the
* sensors native bus width
*/
if (width_flag != SOCAM_DATAWIDTH_10)
return -EINVAL;
}
flags = soc_camera_apply_sensor_flags(icl, flags);
if (flags & SOCAM_PCLK_SAMPLE_FALLING)
pixclk |= 0x10;
if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH))
pixclk |= 0x1;
if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH))
pixclk |= 0x2;
ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk);
if (ret < 0)
return ret;
if (!(flags & SOCAM_MASTER))
mt9v022->chip_control &= ~0x8;
ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
if (ret < 0)
return ret;
dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
pixclk, mt9v022->chip_control);
return 0;
}
static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
{
struct soc_camera_link *icl = to_soc_camera_link(icd);
unsigned int flags = SOCAM_MASTER | SOCAM_SLAVE |
SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
SOCAM_DATA_ACTIVE_HIGH;
if (icl->query_bus_param)
flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK;
else
flags |= SOCAM_DATAWIDTH_10;
return soc_camera_apply_sensor_flags(icl, flags);
}
static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
......@@ -389,7 +332,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
/*
* The caller provides a supported format, as verified per call to
* icd->try_fmt(), datawidth is from our supported format list
* .try_mbus_fmt(), datawidth is from our supported format list
*/
switch (mf->code) {
case V4L2_MBUS_FMT_Y8_1X8:
......@@ -502,236 +445,131 @@ static int mt9v022_s_register(struct v4l2_subdev *sd,
}
#endif
static const struct v4l2_queryctrl mt9v022_controls[] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Flip Vertically",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
}, {
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Flip Horizontally",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
}, {
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Analog Gain",
.minimum = 64,
.maximum = 127,
.step = 1,
.default_value = 64,
.flags = V4L2_CTRL_FLAG_SLIDER,
}, {
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Exposure",
.minimum = 1,
.maximum = 255,
.step = 1,
.default_value = 255,
.flags = V4L2_CTRL_FLAG_SLIDER,
}, {
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Automatic Gain",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1,
}, {
.id = V4L2_CID_EXPOSURE_AUTO,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Automatic Exposure",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1,
}
};
static struct soc_camera_ops mt9v022_ops = {
.set_bus_param = mt9v022_set_bus_param,
.query_bus_param = mt9v022_query_bus_param,
.controls = mt9v022_controls,
.num_controls = ARRAY_SIZE(mt9v022_controls),
};
static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
struct mt9v022 *mt9v022 = container_of(ctrl->handler,
struct mt9v022, hdl);
struct v4l2_subdev *sd = &mt9v022->subdev;
struct i2c_client *client = v4l2_get_subdevdata(sd);
const struct v4l2_queryctrl *qctrl;
struct v4l2_ctrl *gain = mt9v022->gain;
struct v4l2_ctrl *exp = mt9v022->exposure;
unsigned long range;
int data;
qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
switch (ctrl->id) {
case V4L2_CID_VFLIP:
data = reg_read(client, MT9V022_READ_MODE);
if (data < 0)
return -EIO;
ctrl->value = !!(data & 0x10);
break;
case V4L2_CID_HFLIP:
data = reg_read(client, MT9V022_READ_MODE);
if (data < 0)
return -EIO;
ctrl->value = !!(data & 0x20);
break;
case V4L2_CID_EXPOSURE_AUTO:
data = reg_read(client, MT9V022_AEC_AGC_ENABLE);
if (data < 0)
return -EIO;
ctrl->value = !!(data & 0x1);
break;
case V4L2_CID_AUTOGAIN:
data = reg_read(client, MT9V022_AEC_AGC_ENABLE);
if (data < 0)
return -EIO;
ctrl->value = !!(data & 0x2);
break;
case V4L2_CID_GAIN:
data = reg_read(client, MT9V022_ANALOG_GAIN);
if (data < 0)
return -EIO;
range = qctrl->maximum - qctrl->minimum;
ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum;
break;
case V4L2_CID_EXPOSURE:
range = gain->maximum - gain->minimum;
gain->val = ((data - 16) * range + 24) / 48 + gain->minimum;
return 0;
case V4L2_CID_EXPOSURE_AUTO:
data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH);
if (data < 0)
return -EIO;
range = qctrl->maximum - qctrl->minimum;
ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum;
break;
range = exp->maximum - exp->minimum;
exp->val = ((data - 1) * range + 239) / 479 + exp->minimum;
return 0;
}
return 0;
return -EINVAL;
}
static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
{
int data;
struct mt9v022 *mt9v022 = container_of(ctrl->handler,
struct mt9v022, hdl);
struct v4l2_subdev *sd = &mt9v022->subdev;
struct i2c_client *client = v4l2_get_subdevdata(sd);
const struct v4l2_queryctrl *qctrl;
qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
if (!qctrl)
return -EINVAL;
int data;
switch (ctrl->id) {
case V4L2_CID_VFLIP:
if (ctrl->value)
if (ctrl->val)
data = reg_set(client, MT9V022_READ_MODE, 0x10);
else
data = reg_clear(client, MT9V022_READ_MODE, 0x10);
if (data < 0)
return -EIO;
break;
return 0;
case V4L2_CID_HFLIP:
if (ctrl->value)
if (ctrl->val)
data = reg_set(client, MT9V022_READ_MODE, 0x20);
else
data = reg_clear(client, MT9V022_READ_MODE, 0x20);
if (data < 0)
return -EIO;
break;
case V4L2_CID_GAIN:
/* mt9v022 has minimum == default */
if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
return -EINVAL;
else {
unsigned long range = qctrl->maximum - qctrl->minimum;
return 0;
case V4L2_CID_AUTOGAIN:
if (ctrl->val) {
if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
return -EIO;
} else {
struct v4l2_ctrl *gain = mt9v022->gain;
/* mt9v022 has minimum == default */
unsigned long range = gain->maximum - gain->minimum;
/* Valid values 16 to 64, 32 to 64 must be even. */
unsigned long gain = ((ctrl->value - qctrl->minimum) *
unsigned long gain_val = ((gain->val - gain->minimum) *
48 + range / 2) / range + 16;
if (gain >= 32)
gain &= ~1;
if (gain_val >= 32)
gain_val &= ~1;
/*
* The user wants to set gain manually, hope, she
* knows, what she's doing... Switch AGC off.
*/
if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
return -EIO;
dev_dbg(&client->dev, "Setting gain from %d to %lu\n",
reg_read(client, MT9V022_ANALOG_GAIN), gain);
if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0)
reg_read(client, MT9V022_ANALOG_GAIN), gain_val);
if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0)
return -EIO;
}
break;
case V4L2_CID_EXPOSURE:
/* mt9v022 has maximum == default */
if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
return -EINVAL;
else {
unsigned long range = qctrl->maximum - qctrl->minimum;
unsigned long shutter = ((ctrl->value - qctrl->minimum) *
479 + range / 2) / range + 1;
return 0;
case V4L2_CID_EXPOSURE_AUTO:
if (ctrl->val == V4L2_EXPOSURE_AUTO) {
data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1);
} else {
struct v4l2_ctrl *exp = mt9v022->exposure;
unsigned long range = exp->maximum - exp->minimum;
unsigned long shutter = ((exp->val - exp->minimum) *
479 + range / 2) / range + 1;
/*
* The user wants to set shutter width manually, hope,
* she knows, what she's doing... Switch AEC off.
*/
if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0)
data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1);
if (data < 0)
return -EIO;
dev_dbg(&client->dev, "Shutter width from %d to %lu\n",
reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
shutter);
reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
shutter);
if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
shutter) < 0)
shutter) < 0)
return -EIO;
}
break;
case V4L2_CID_AUTOGAIN:
if (ctrl->value)
data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2);
else
data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2);
if (data < 0)
return -EIO;
break;
case V4L2_CID_EXPOSURE_AUTO:
if (ctrl->value)
data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1);
else
data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1);
if (data < 0)
return -EIO;
break;
return 0;
}
return 0;
return -EINVAL;
}
/*
* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one
*/
static int mt9v022_video_probe(struct soc_camera_device *icd,
struct i2c_client *client)
static int mt9v022_video_probe(struct i2c_client *client)
{
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct soc_camera_link *icl = to_soc_camera_link(icd);
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
s32 data;
int ret;
unsigned long flags;
/* We must have a parent by now. And it cannot be a wrong one. */
BUG_ON(!icd->parent ||
to_soc_camera_host(icd->parent)->nr != icd->iface);
/* Read out the chip version register */
data = reg_read(client, MT9V022_CHIP_VERSION);
......@@ -805,16 +643,6 @@ static int mt9v022_video_probe(struct soc_camera_device *icd,
return ret;
}
static void mt9v022_video_remove(struct soc_camera_device *icd)
{
struct soc_camera_link *icl = to_soc_camera_link(icd);
dev_dbg(icd->pdev, "Video removed: %p, %p\n",
icd->parent, icd->vdev);
if (icl->free_bus)
icl->free_bus(icl);
}
static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
......@@ -825,9 +653,12 @@ static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
return 0;
}
static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = {
.g_volatile_ctrl = mt9v022_g_volatile_ctrl,
.s_ctrl = mt9v022_s_ctrl,
};
static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
.g_ctrl = mt9v022_g_ctrl,
.s_ctrl = mt9v022_s_ctrl,
.g_chip_ident = mt9v022_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9v022_g_register,
......@@ -848,6 +679,72 @@ static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
return 0;
}
static int mt9v022_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE |
V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
cfg->flags = soc_camera_apply_board_flags(icl, cfg);
return 0;
}
static int mt9v022_s_mbus_config(struct v4l2_subdev *sd,
const struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
struct mt9v022 *mt9v022 = to_mt9v022(client);
unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample;
int ret;
u16 pixclk = 0;
if (icl->set_bus_param) {
ret = icl->set_bus_param(icl, 1 << (bps - 1));
if (ret)
return ret;
} else if (bps != 10) {
/*
* Without board specific bus width settings we only support the
* sensors native bus width
*/
return -EINVAL;
}
if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
pixclk |= 0x10;
if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH))
pixclk |= 0x1;
if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH))
pixclk |= 0x2;
ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk);
if (ret < 0)
return ret;
if (!(flags & V4L2_MBUS_MASTER))
mt9v022->chip_control &= ~0x8;
ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
if (ret < 0)
return ret;
dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
pixclk, mt9v022->chip_control);
return 0;
}
static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
.s_stream = mt9v022_s_stream,
.s_mbus_fmt = mt9v022_s_fmt,
......@@ -857,6 +754,8 @@ static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
.g_crop = mt9v022_g_crop,
.cropcap = mt9v022_cropcap,
.enum_mbus_fmt = mt9v022_enum_fmt,
.g_mbus_config = mt9v022_g_mbus_config,
.s_mbus_config = mt9v022_s_mbus_config,
};
static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = {
......@@ -873,17 +772,10 @@ static int mt9v022_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9v022 *mt9v022;
struct soc_camera_device *icd = client->dev.platform_data;
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct soc_camera_link *icl;
int ret;
if (!icd) {
dev_err(&client->dev, "MT9V022: missing soc-camera data!\n");
return -EINVAL;
}
icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "MT9V022 driver needs platform data\n");
return -EINVAL;
......@@ -900,10 +792,39 @@ static int mt9v022_probe(struct i2c_client *client,
return -ENOMEM;
v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops);
v4l2_ctrl_handler_init(&mt9v022->hdl, 6);
v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
V4L2_CID_GAIN, 0, 127, 1, 64);
/*
* Simulated autoexposure. If enabled, we calculate shutter width
* ourselves in the driver based on vertical blanking and frame width
*/
mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl,
&mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
V4L2_EXPOSURE_AUTO);
mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
V4L2_CID_EXPOSURE, 1, 255, 1, 255);
mt9v022->subdev.ctrl_handler = &mt9v022->hdl;
if (mt9v022->hdl.error) {
int err = mt9v022->hdl.error;
kfree(mt9v022);
return err;
}
v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure,
V4L2_EXPOSURE_MANUAL, true);
v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true);
mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
icd->ops = &mt9v022_ops;
/*
* MT9V022 _really_ corrupts the first read out line.
* TODO: verify on i.MX31
......@@ -914,9 +835,9 @@ static int mt9v022_probe(struct i2c_client *client,
mt9v022->rect.width = MT9V022_MAX_WIDTH;
mt9v022->rect.height = MT9V022_MAX_HEIGHT;
ret = mt9v022_video_probe(icd, client);
ret = mt9v022_video_probe(client);
if (ret) {
icd->ops = NULL;
v4l2_ctrl_handler_free(&mt9v022->hdl);
kfree(mt9v022);
}
......@@ -926,10 +847,12 @@ static int mt9v022_probe(struct i2c_client *client,
static int mt9v022_remove(struct i2c_client *client)
{
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct soc_camera_device *icd = client->dev.platform_data;
struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
icd->ops = NULL;
mt9v022_video_remove(icd);
v4l2_device_unregister_subdev(&mt9v022->subdev);
if (icl->free_bus)
icl->free_bus(icl);
v4l2_ctrl_handler_free(&mt9v022->hdl);
kfree(mt9v022);
return 0;
......
......@@ -78,11 +78,10 @@
#define CSI_IRQ_MASK (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \
CSISR_STATFF_INT | CSISR_RXFF_INT | CSISR_SOF_INT)
#define CSI_BUS_FLAGS (SOCAM_MASTER | SOCAM_HSYNC_ACTIVE_HIGH | \
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | \
SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \
SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW | \
SOCAM_DATAWIDTH_8)
#define CSI_BUS_FLAGS (V4L2_MBUS_MASTER | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | \
V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \
V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_LOW)
#define MAX_VIDEO_MEM 16 /* Video memory limit in megabytes */
......@@ -490,59 +489,73 @@ static int mx1_camera_set_crop(struct soc_camera_device *icd,
static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx1_camera_dev *pcdev = ici->priv;
unsigned long camera_flags, common_flags;
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
unsigned long common_flags;
unsigned int csicr1;
int ret;
camera_flags = icd->ops->query_bus_param(icd);
/* MX1 supports only 8bit buswidth */
common_flags = soc_camera_bus_param_compatible(camera_flags,
CSI_BUS_FLAGS);
if (!common_flags)
return -EINVAL;
ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
if (!ret) {
common_flags = soc_mbus_config_compatible(&cfg, CSI_BUS_FLAGS);
if (!common_flags) {
dev_warn(icd->parent,
"Flags incompatible: camera 0x%x, host 0x%x\n",
cfg.flags, CSI_BUS_FLAGS);
return -EINVAL;
}
} else if (ret != -ENOIOCTLCMD) {
return ret;
} else {
common_flags = CSI_BUS_FLAGS;
}
/* Make choises, based on platform choice */
if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
(common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
(common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
if (!pcdev->pdata ||
pcdev->pdata->flags & MX1_CAMERA_VSYNC_HIGH)
common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
else
common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
}
if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
(common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
(common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
if (!pcdev->pdata ||
pcdev->pdata->flags & MX1_CAMERA_PCLK_RISING)
common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
else
common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
}
if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) &&
(common_flags & SOCAM_DATA_ACTIVE_LOW)) {
if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) &&
(common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) {
if (!pcdev->pdata ||
pcdev->pdata->flags & MX1_CAMERA_DATA_HIGH)
common_flags &= ~SOCAM_DATA_ACTIVE_LOW;
common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW;
else
common_flags &= ~SOCAM_DATA_ACTIVE_HIGH;
common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH;
}
ret = icd->ops->set_bus_param(icd, common_flags);
if (ret < 0)
cfg.flags = common_flags;
ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
if (ret < 0 && ret != -ENOIOCTLCMD) {
dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n",
common_flags, ret);
return ret;
}
csicr1 = __raw_readl(pcdev->base + CSICR1);
if (common_flags & SOCAM_PCLK_SAMPLE_RISING)
if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
csicr1 |= CSICR1_REDGE;
if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH)
if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
csicr1 |= CSICR1_SOF_POL;
if (common_flags & SOCAM_DATA_ACTIVE_LOW)
if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)
csicr1 |= CSICR1_DATA_POL;
__raw_writel(csicr1, pcdev->base + CSICR1);
......
......@@ -686,16 +686,15 @@ static void mx2_camera_init_videobuf(struct videobuf_queue *q,
icd, &icd->video_lock);
}
#define MX2_BUS_FLAGS (SOCAM_DATAWIDTH_8 | \
SOCAM_MASTER | \
SOCAM_VSYNC_ACTIVE_HIGH | \
SOCAM_VSYNC_ACTIVE_LOW | \
SOCAM_HSYNC_ACTIVE_HIGH | \
SOCAM_HSYNC_ACTIVE_LOW | \
SOCAM_PCLK_SAMPLE_RISING | \
SOCAM_PCLK_SAMPLE_FALLING | \
SOCAM_DATA_ACTIVE_HIGH | \
SOCAM_DATA_ACTIVE_LOW)
#define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \
V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
V4L2_MBUS_VSYNC_ACTIVE_LOW | \
V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
V4L2_MBUS_HSYNC_ACTIVE_LOW | \
V4L2_MBUS_PCLK_SAMPLE_RISING | \
V4L2_MBUS_PCLK_SAMPLE_FALLING | \
V4L2_MBUS_DATA_ACTIVE_HIGH | \
V4L2_MBUS_DATA_ACTIVE_LOW)
static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
{
......@@ -770,46 +769,59 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
static int mx2_camera_set_bus_param(struct soc_camera_device *icd,
__u32 pixfmt)
{
struct soc_camera_host *ici =
to_soc_camera_host(icd->parent);
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx2_camera_dev *pcdev = ici->priv;
unsigned long camera_flags, common_flags;
int ret = 0;
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
unsigned long common_flags;
int ret;
int bytesperline;
u32 csicr1 = pcdev->csicr1;
camera_flags = icd->ops->query_bus_param(icd);
common_flags = soc_camera_bus_param_compatible(camera_flags,
MX2_BUS_FLAGS);
if (!common_flags)
return -EINVAL;
ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
if (!ret) {
common_flags = soc_mbus_config_compatible(&cfg, MX2_BUS_FLAGS);
if (!common_flags) {
dev_warn(icd->parent,
"Flags incompatible: camera 0x%x, host 0x%x\n",
cfg.flags, MX2_BUS_FLAGS);
return -EINVAL;
}
} else if (ret != -ENOIOCTLCMD) {
return ret;
} else {
common_flags = MX2_BUS_FLAGS;
}
if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
(common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
(common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH)
common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
else
common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
}
if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
(common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
(common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING)
common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
else
common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
}
ret = icd->ops->set_bus_param(icd, common_flags);
if (ret < 0)
cfg.flags = common_flags;
ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
if (ret < 0 && ret != -ENOIOCTLCMD) {
dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n",
common_flags, ret);
return ret;
}
if (common_flags & SOCAM_PCLK_SAMPLE_RISING)
if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
csicr1 |= CSICR1_REDGE;
if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH)
if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
csicr1 |= CSICR1_SOF_POL;
if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH)
if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
csicr1 |= CSICR1_HSYNC_POL;
if (pcdev->platform_flags & MX2_CAMERA_SWAP16)
csicr1 |= CSICR1_SWAP16_EN;
......
此差异已折叠。
......@@ -833,6 +833,15 @@ static void omap_vout_buffer_release(struct videobuf_queue *q,
/*
* File operations
*/
static unsigned int omap_vout_poll(struct file *file,
struct poll_table_struct *wait)
{
struct omap_vout_device *vout = file->private_data;
struct videobuf_queue *q = &vout->vbq;
return videobuf_poll_stream(file, q, wait);
}
static void omap_vout_vm_open(struct vm_area_struct *vma)
{
struct omap_vout_device *vout = vma->vm_private_data;
......@@ -1861,6 +1870,7 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = {
static const struct v4l2_file_operations omap_vout_fops = {
.owner = THIS_MODULE,
.poll = omap_vout_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = omap_vout_mmap,
.open = omap_vout_open,
......
......@@ -102,10 +102,10 @@
/* end of OMAP1 Camera Interface registers */
#define SOCAM_BUS_FLAGS (SOCAM_MASTER | \
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | \
SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \
SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8)
#define SOCAM_BUS_FLAGS (V4L2_MBUS_MASTER | \
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \
V4L2_MBUS_DATA_ACTIVE_HIGH)
#define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1)
......@@ -1438,41 +1438,55 @@ static int omap1_cam_querycap(struct soc_camera_host *ici,
static int omap1_cam_set_bus_param(struct soc_camera_device *icd,
__u32 pixfmt)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->parent;
struct soc_camera_host *ici = to_soc_camera_host(dev);
struct omap1_cam_dev *pcdev = ici->priv;
const struct soc_camera_format_xlate *xlate;
const struct soc_mbus_pixelfmt *fmt;
unsigned long camera_flags, common_flags;
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
unsigned long common_flags;
u32 ctrlclock, mode;
int ret;
camera_flags = icd->ops->query_bus_param(icd);
common_flags = soc_camera_bus_param_compatible(camera_flags,
SOCAM_BUS_FLAGS);
if (!common_flags)
return -EINVAL;
ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
if (!ret) {
common_flags = soc_mbus_config_compatible(&cfg, SOCAM_BUS_FLAGS);
if (!common_flags) {
dev_warn(dev,
"Flags incompatible: camera 0x%x, host 0x%x\n",
cfg.flags, SOCAM_BUS_FLAGS);
return -EINVAL;
}
} else if (ret != -ENOIOCTLCMD) {
return ret;
} else {
common_flags = SOCAM_BUS_FLAGS;
}
/* Make choices, possibly based on platform configuration */
if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
(common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
(common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
if (!pcdev->pdata ||
pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING)
common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
else
common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
}
ret = icd->ops->set_bus_param(icd, common_flags);
if (ret < 0)
cfg.flags = common_flags;
ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
if (ret < 0 && ret != -ENOIOCTLCMD) {
dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n",
common_flags, ret);
return ret;
}
ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
if (ctrlclock & LCLK_EN)
CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
if (common_flags & SOCAM_PCLK_SAMPLE_RISING) {
if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) {
dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n");
ctrlclock |= POLCLK;
} else {
......@@ -1565,10 +1579,10 @@ static int __init omap1_cam_probe(struct platform_device *pdev)
pcdev->clk = clk;
pcdev->pdata = pdev->dev.platform_data;
pcdev->pflags = pcdev->pdata->flags;
if (pcdev->pdata)
if (pcdev->pdata) {
pcdev->pflags = pcdev->pdata->flags;
pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000;
}
switch (pcdev->camexclk) {
case 6000000:
......@@ -1578,6 +1592,7 @@ static int __init omap1_cam_probe(struct platform_device *pdev)
case 24000000:
break;
default:
/* pcdev->camexclk != 0 => pcdev->pdata != NULL */
dev_warn(&pdev->dev,
"Incorrect sensor clock frequency %ld kHz, "
"should be one of 0, 6, 8, 9.6, 12 or 24 MHz, "
......@@ -1585,8 +1600,7 @@ static int __init omap1_cam_probe(struct platform_device *pdev)
pcdev->pdata->camexclk_khz);
pcdev->camexclk = 0;
case 0:
dev_info(&pdev->dev,
"Not providing sensor clock\n");
dev_info(&pdev->dev, "Not providing sensor clock\n");
}
INIT_LIST_HEAD(&pcdev->capture);
......@@ -1716,5 +1730,5 @@ MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg");
MODULE_DESCRIPTION("OMAP1 Camera Interface driver");
MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
MODULE_LICENSE("GPL v2");
MODULE_LICENSE(DRIVER_VERSION);
MODULE_VERSION(DRIVER_VERSION);
MODULE_ALIAS("platform:" DRIVER_NAME);
......@@ -1704,6 +1704,7 @@ static int isp_register_entities(struct isp_device *isp)
isp->media_dev.dev = isp->dev;
strlcpy(isp->media_dev.model, "TI OMAP3 ISP",
sizeof(isp->media_dev.model));
isp->media_dev.hw_revision = isp->revision;
isp->media_dev.link_notify = isp_pipeline_link_notify;
ret = media_device_register(&isp->media_dev);
if (ret < 0) {
......@@ -2210,6 +2211,8 @@ static int isp_probe(struct platform_device *pdev)
regulator_put(isp->isp_csiphy2.vdd);
regulator_put(isp->isp_csiphy1.vdd);
platform_set_drvdata(pdev, NULL);
mutex_destroy(&isp->isp_mutex);
kfree(isp);
return ret;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册