Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: [media] v1.88 DM04/QQBOX Move remote to use rc_core dvb-usb-remote [media] Add missing include guard to header file [media] Inlined functions should be static [media] Remove invalid parameter description [media] cpia2: fix warning about invalid trigraph sequence [media] s5p-csis: Add missing dependency on PLAT_S5P [media] gspca/kinect: wrap gspca_debug with GSPCA_DEBUG [media] fintek-cir: new driver for Fintek LPC SuperIO CIR function [media] uvcvideo: Connect video devices to media entities [media] uvcvideo: Register subdevices for each entity [media] uvcvideo: Register a v4l2_device [media] add V4L2-PIX-FMT-SRGGB12 & friends to docbook [media] Documentation/DocBook: Rename media fops xml files [media] Media DocBook: fix validation errors [media] wl12xx: g_volatile_ctrl fix: wrong field set [media] fix kconfig dependency warning for VIDEO_TIMBERDALE [media] dm1105: GPIO handling added, I2C on GPIO added, LNB control through GPIO reworked [media] Add support for M-5MOLS 8 Mega Pixel camera ISP
This commit is contained in:
commit
c0880dcded
|
@ -141,13 +141,15 @@ struct dtv_properties {
|
||||||
</row></tbody></tgroup></informaltable>
|
</row></tbody></tgroup></informaltable>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title>Property types</title>
|
||||||
<para>
|
<para>
|
||||||
On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
|
On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
|
||||||
the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to
|
the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to
|
||||||
get/set up to 64 properties. The actual meaning of each property is described on the next sections.
|
get/set up to 64 properties. The actual meaning of each property is described on the next sections.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>The Available frontend property types are:</para>
|
<para>The available frontend property types are:</para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
#define DTV_UNDEFINED 0
|
#define DTV_UNDEFINED 0
|
||||||
#define DTV_TUNE 1
|
#define DTV_TUNE 1
|
||||||
|
@ -193,6 +195,7 @@ get/set up to 64 properties. The actual meaning of each property is described on
|
||||||
#define DTV_ISDBT_LAYER_ENABLED 41
|
#define DTV_ISDBT_LAYER_ENABLED 41
|
||||||
#define DTV_ISDBS_TS_ID 42
|
#define DTV_ISDBS_TS_ID 42
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section id="fe_property_common">
|
<section id="fe_property_common">
|
||||||
<title>Parameters that are common to all Digital TV standards</title>
|
<title>Parameters that are common to all Digital TV standards</title>
|
||||||
|
|
|
@ -293,6 +293,7 @@
|
||||||
<!ENTITY sub-yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
|
<!ENTITY sub-yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
|
||||||
<!ENTITY sub-yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
|
<!ENTITY sub-yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
|
||||||
<!ENTITY sub-srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
|
<!ENTITY sub-srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
|
||||||
|
<!ENTITY sub-srggb12 SYSTEM "v4l/pixfmt-srggb12.xml">
|
||||||
<!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
|
<!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
|
||||||
<!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml">
|
<!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml">
|
||||||
<!ENTITY sub-y12 SYSTEM "v4l/pixfmt-y12.xml">
|
<!ENTITY sub-y12 SYSTEM "v4l/pixfmt-y12.xml">
|
||||||
|
@ -373,9 +374,9 @@
|
||||||
<!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">
|
<!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">
|
||||||
|
|
||||||
<!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
|
<!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
|
||||||
<!ENTITY sub-media-open SYSTEM "v4l/media-func-open.xml">
|
<!ENTITY sub-media-func-open SYSTEM "v4l/media-func-open.xml">
|
||||||
<!ENTITY sub-media-close SYSTEM "v4l/media-func-close.xml">
|
<!ENTITY sub-media-func-close SYSTEM "v4l/media-func-close.xml">
|
||||||
<!ENTITY sub-media-ioctl SYSTEM "v4l/media-func-ioctl.xml">
|
<!ENTITY sub-media-func-ioctl SYSTEM "v4l/media-func-ioctl.xml">
|
||||||
<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
|
<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
|
||||||
<!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
|
<!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
|
||||||
<!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
|
<!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
|
||||||
|
|
|
@ -78,9 +78,9 @@
|
||||||
<appendix id="media-user-func">
|
<appendix id="media-user-func">
|
||||||
<title>Function Reference</title>
|
<title>Function Reference</title>
|
||||||
<!-- Keep this alphabetically sorted. -->
|
<!-- Keep this alphabetically sorted. -->
|
||||||
&sub-media-open;
|
&sub-media-func-open;
|
||||||
&sub-media-close;
|
&sub-media-func-close;
|
||||||
&sub-media-ioctl;
|
&sub-media-func-ioctl;
|
||||||
<!-- All ioctls go here. -->
|
<!-- All ioctls go here. -->
|
||||||
&sub-media-ioc-device-info;
|
&sub-media-ioc-device-info;
|
||||||
&sub-media-ioc-enum-entities;
|
&sub-media-ioc-enum-entities;
|
||||||
|
|
|
@ -673,6 +673,7 @@ access the palette, this must be done with ioctls of the Linux framebuffer API.<
|
||||||
&sub-srggb8;
|
&sub-srggb8;
|
||||||
&sub-sbggr16;
|
&sub-sbggr16;
|
||||||
&sub-srggb10;
|
&sub-srggb10;
|
||||||
|
&sub-srggb12;
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="yuv-formats">
|
<section id="yuv-formats">
|
||||||
|
|
|
@ -2531,14 +2531,14 @@
|
||||||
<constant>_JPEG</constant> prefix the format code is made of
|
<constant>_JPEG</constant> prefix the format code is made of
|
||||||
the following information.
|
the following information.
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem>The number of bus samples per entropy encoded byte.</listitem>
|
<listitem><para>The number of bus samples per entropy encoded byte.</para></listitem>
|
||||||
<listitem>The bus width.</listitem>
|
<listitem><para>The bus width.</para></listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>For instance, for a JPEG baseline process and an 8-bit bus width
|
<para>For instance, for a JPEG baseline process and an 8-bit bus width
|
||||||
the format will be named <constant>V4L2_MBUS_FMT_JPEG_1X8</constant>.
|
the format will be named <constant>V4L2_MBUS_FMT_JPEG_1X8</constant>.
|
||||||
</para>
|
</para>
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>The following table lists existing JPEG compressed formats.</para>
|
<para>The following table lists existing JPEG compressed formats.</para>
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/i2c-algo-bit.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
@ -54,6 +55,7 @@
|
||||||
#define DM1105_BOARD_DVBWORLD_2002 1
|
#define DM1105_BOARD_DVBWORLD_2002 1
|
||||||
#define DM1105_BOARD_DVBWORLD_2004 2
|
#define DM1105_BOARD_DVBWORLD_2004 2
|
||||||
#define DM1105_BOARD_AXESS_DM05 3
|
#define DM1105_BOARD_AXESS_DM05 3
|
||||||
|
#define DM1105_BOARD_UNBRANDED_I2C_ON_GPIO 4
|
||||||
|
|
||||||
/* ----------------------------------------------- */
|
/* ----------------------------------------------- */
|
||||||
/*
|
/*
|
||||||
|
@ -157,22 +159,38 @@
|
||||||
#define DM1105_MAX 0x04
|
#define DM1105_MAX 0x04
|
||||||
|
|
||||||
#define DRIVER_NAME "dm1105"
|
#define DRIVER_NAME "dm1105"
|
||||||
|
#define DM1105_I2C_GPIO_NAME "dm1105-gpio"
|
||||||
|
|
||||||
#define DM1105_DMA_PACKETS 47
|
#define DM1105_DMA_PACKETS 47
|
||||||
#define DM1105_DMA_PACKET_LENGTH (128*4)
|
#define DM1105_DMA_PACKET_LENGTH (128*4)
|
||||||
#define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS)
|
#define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS)
|
||||||
|
|
||||||
|
/* */
|
||||||
|
#define GPIO08 (1 << 8)
|
||||||
|
#define GPIO13 (1 << 13)
|
||||||
|
#define GPIO14 (1 << 14)
|
||||||
|
#define GPIO15 (1 << 15)
|
||||||
|
#define GPIO16 (1 << 16)
|
||||||
|
#define GPIO17 (1 << 17)
|
||||||
|
#define GPIO_ALL 0x03ffff
|
||||||
|
|
||||||
/* GPIO's for LNB power control */
|
/* GPIO's for LNB power control */
|
||||||
#define DM1105_LNB_MASK 0x00000000
|
#define DM1105_LNB_MASK (GPIO_ALL & ~(GPIO14 | GPIO13))
|
||||||
#define DM1105_LNB_OFF 0x00020000
|
#define DM1105_LNB_OFF GPIO17
|
||||||
#define DM1105_LNB_13V 0x00010100
|
#define DM1105_LNB_13V (GPIO16 | GPIO08)
|
||||||
#define DM1105_LNB_18V 0x00000100
|
#define DM1105_LNB_18V GPIO08
|
||||||
|
|
||||||
/* GPIO's for LNB power control for Axess DM05 */
|
/* GPIO's for LNB power control for Axess DM05 */
|
||||||
#define DM05_LNB_MASK 0x00000000
|
#define DM05_LNB_MASK (GPIO_ALL & ~(GPIO14 | GPIO13))
|
||||||
#define DM05_LNB_OFF 0x00020000/* actually 13v */
|
#define DM05_LNB_OFF GPIO17/* actually 13v */
|
||||||
#define DM05_LNB_13V 0x00020000
|
#define DM05_LNB_13V GPIO17
|
||||||
#define DM05_LNB_18V 0x00030000
|
#define DM05_LNB_18V (GPIO17 | GPIO16)
|
||||||
|
|
||||||
|
/* GPIO's for LNB power control for unbranded with I2C on GPIO */
|
||||||
|
#define UNBR_LNB_MASK (GPIO17 | GPIO16)
|
||||||
|
#define UNBR_LNB_OFF 0
|
||||||
|
#define UNBR_LNB_13V GPIO17
|
||||||
|
#define UNBR_LNB_18V (GPIO17 | GPIO16)
|
||||||
|
|
||||||
static unsigned int card[] = {[0 ... 3] = UNSET };
|
static unsigned int card[] = {[0 ... 3] = UNSET };
|
||||||
module_param_array(card, int, NULL, 0444);
|
module_param_array(card, int, NULL, 0444);
|
||||||
|
@ -188,6 +206,10 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||||
|
|
||||||
struct dm1105_board {
|
struct dm1105_board {
|
||||||
char *name;
|
char *name;
|
||||||
|
struct {
|
||||||
|
u32 mask, off, v13, v18;
|
||||||
|
} lnb;
|
||||||
|
u32 gpio_scl, gpio_sda;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dm1105_subid {
|
struct dm1105_subid {
|
||||||
|
@ -199,15 +221,50 @@ struct dm1105_subid {
|
||||||
static const struct dm1105_board dm1105_boards[] = {
|
static const struct dm1105_board dm1105_boards[] = {
|
||||||
[DM1105_BOARD_UNKNOWN] = {
|
[DM1105_BOARD_UNKNOWN] = {
|
||||||
.name = "UNKNOWN/GENERIC",
|
.name = "UNKNOWN/GENERIC",
|
||||||
|
.lnb = {
|
||||||
|
.mask = DM1105_LNB_MASK,
|
||||||
|
.off = DM1105_LNB_OFF,
|
||||||
|
.v13 = DM1105_LNB_13V,
|
||||||
|
.v18 = DM1105_LNB_18V,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[DM1105_BOARD_DVBWORLD_2002] = {
|
[DM1105_BOARD_DVBWORLD_2002] = {
|
||||||
.name = "DVBWorld PCI 2002",
|
.name = "DVBWorld PCI 2002",
|
||||||
|
.lnb = {
|
||||||
|
.mask = DM1105_LNB_MASK,
|
||||||
|
.off = DM1105_LNB_OFF,
|
||||||
|
.v13 = DM1105_LNB_13V,
|
||||||
|
.v18 = DM1105_LNB_18V,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[DM1105_BOARD_DVBWORLD_2004] = {
|
[DM1105_BOARD_DVBWORLD_2004] = {
|
||||||
.name = "DVBWorld PCI 2004",
|
.name = "DVBWorld PCI 2004",
|
||||||
|
.lnb = {
|
||||||
|
.mask = DM1105_LNB_MASK,
|
||||||
|
.off = DM1105_LNB_OFF,
|
||||||
|
.v13 = DM1105_LNB_13V,
|
||||||
|
.v18 = DM1105_LNB_18V,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[DM1105_BOARD_AXESS_DM05] = {
|
[DM1105_BOARD_AXESS_DM05] = {
|
||||||
.name = "Axess/EasyTv DM05",
|
.name = "Axess/EasyTv DM05",
|
||||||
|
.lnb = {
|
||||||
|
.mask = DM05_LNB_MASK,
|
||||||
|
.off = DM05_LNB_OFF,
|
||||||
|
.v13 = DM05_LNB_13V,
|
||||||
|
.v18 = DM05_LNB_18V,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[DM1105_BOARD_UNBRANDED_I2C_ON_GPIO] = {
|
||||||
|
.name = "Unbranded DM1105 with i2c on GPIOs",
|
||||||
|
.lnb = {
|
||||||
|
.mask = UNBR_LNB_MASK,
|
||||||
|
.off = UNBR_LNB_OFF,
|
||||||
|
.v13 = UNBR_LNB_13V,
|
||||||
|
.v18 = UNBR_LNB_18V,
|
||||||
|
},
|
||||||
|
.gpio_scl = GPIO14,
|
||||||
|
.gpio_sda = GPIO13,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -293,6 +350,8 @@ struct dm1105_dev {
|
||||||
|
|
||||||
/* i2c */
|
/* i2c */
|
||||||
struct i2c_adapter i2c_adap;
|
struct i2c_adapter i2c_adap;
|
||||||
|
struct i2c_adapter i2c_bb_adap;
|
||||||
|
struct i2c_algo_bit_data i2c_bit;
|
||||||
|
|
||||||
/* irq */
|
/* irq */
|
||||||
struct work_struct work;
|
struct work_struct work;
|
||||||
|
@ -328,6 +387,103 @@ struct dm1105_dev {
|
||||||
#define dm_setl(reg, bit) dm_andorl((reg), (bit), (bit))
|
#define dm_setl(reg, bit) dm_andorl((reg), (bit), (bit))
|
||||||
#define dm_clearl(reg, bit) dm_andorl((reg), (bit), 0)
|
#define dm_clearl(reg, bit) dm_andorl((reg), (bit), 0)
|
||||||
|
|
||||||
|
/* The chip has 18 GPIOs. In HOST mode GPIO's used as 15 bit address lines,
|
||||||
|
so we can use only 3 GPIO's from GPIO15 to GPIO17.
|
||||||
|
Here I don't check whether HOST is enebled as it is not implemented yet.
|
||||||
|
*/
|
||||||
|
static void dm1105_gpio_set(struct dm1105_dev *dev, u32 mask)
|
||||||
|
{
|
||||||
|
if (mask & 0xfffc0000)
|
||||||
|
printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
|
||||||
|
|
||||||
|
if (mask & 0x0003ffff)
|
||||||
|
dm_setl(DM1105_GPIOVAL, mask & 0x0003ffff);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dm1105_gpio_clear(struct dm1105_dev *dev, u32 mask)
|
||||||
|
{
|
||||||
|
if (mask & 0xfffc0000)
|
||||||
|
printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
|
||||||
|
|
||||||
|
if (mask & 0x0003ffff)
|
||||||
|
dm_clearl(DM1105_GPIOVAL, mask & 0x0003ffff);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dm1105_gpio_andor(struct dm1105_dev *dev, u32 mask, u32 val)
|
||||||
|
{
|
||||||
|
if (mask & 0xfffc0000)
|
||||||
|
printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
|
||||||
|
|
||||||
|
if (mask & 0x0003ffff)
|
||||||
|
dm_andorl(DM1105_GPIOVAL, mask & 0x0003ffff, val);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 dm1105_gpio_get(struct dm1105_dev *dev, u32 mask)
|
||||||
|
{
|
||||||
|
if (mask & 0xfffc0000)
|
||||||
|
printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
|
||||||
|
|
||||||
|
if (mask & 0x0003ffff)
|
||||||
|
return dm_readl(DM1105_GPIOVAL) & mask & 0x0003ffff;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dm1105_gpio_enable(struct dm1105_dev *dev, u32 mask, int asoutput)
|
||||||
|
{
|
||||||
|
if (mask & 0xfffc0000)
|
||||||
|
printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
|
||||||
|
|
||||||
|
if ((mask & 0x0003ffff) && asoutput)
|
||||||
|
dm_clearl(DM1105_GPIOCTR, mask & 0x0003ffff);
|
||||||
|
else if ((mask & 0x0003ffff) && !asoutput)
|
||||||
|
dm_setl(DM1105_GPIOCTR, mask & 0x0003ffff);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dm1105_setline(struct dm1105_dev *dev, u32 line, int state)
|
||||||
|
{
|
||||||
|
if (state)
|
||||||
|
dm1105_gpio_enable(dev, line, 0);
|
||||||
|
else {
|
||||||
|
dm1105_gpio_enable(dev, line, 1);
|
||||||
|
dm1105_gpio_clear(dev, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dm1105_setsda(void *data, int state)
|
||||||
|
{
|
||||||
|
struct dm1105_dev *dev = data;
|
||||||
|
|
||||||
|
dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_sda, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dm1105_setscl(void *data, int state)
|
||||||
|
{
|
||||||
|
struct dm1105_dev *dev = data;
|
||||||
|
|
||||||
|
dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_scl, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dm1105_getsda(void *data)
|
||||||
|
{
|
||||||
|
struct dm1105_dev *dev = data;
|
||||||
|
|
||||||
|
return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_sda)
|
||||||
|
? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dm1105_getscl(void *data)
|
||||||
|
{
|
||||||
|
struct dm1105_dev *dev = data;
|
||||||
|
|
||||||
|
return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_scl)
|
||||||
|
? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
|
static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||||
struct i2c_msg *msgs, int num)
|
struct i2c_msg *msgs, int num)
|
||||||
{
|
{
|
||||||
|
@ -436,31 +592,20 @@ static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe)
|
||||||
static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||||||
{
|
{
|
||||||
struct dm1105_dev *dev = frontend_to_dm1105_dev(fe);
|
struct dm1105_dev *dev = frontend_to_dm1105_dev(fe);
|
||||||
u32 lnb_mask, lnb_13v, lnb_18v, lnb_off;
|
|
||||||
|
|
||||||
switch (dev->boardnr) {
|
dm1105_gpio_enable(dev, dm1105_boards[dev->boardnr].lnb.mask, 1);
|
||||||
case DM1105_BOARD_AXESS_DM05:
|
|
||||||
lnb_mask = DM05_LNB_MASK;
|
|
||||||
lnb_off = DM05_LNB_OFF;
|
|
||||||
lnb_13v = DM05_LNB_13V;
|
|
||||||
lnb_18v = DM05_LNB_18V;
|
|
||||||
break;
|
|
||||||
case DM1105_BOARD_DVBWORLD_2002:
|
|
||||||
case DM1105_BOARD_DVBWORLD_2004:
|
|
||||||
default:
|
|
||||||
lnb_mask = DM1105_LNB_MASK;
|
|
||||||
lnb_off = DM1105_LNB_OFF;
|
|
||||||
lnb_13v = DM1105_LNB_13V;
|
|
||||||
lnb_18v = DM1105_LNB_18V;
|
|
||||||
}
|
|
||||||
|
|
||||||
dm_writel(DM1105_GPIOCTR, lnb_mask);
|
|
||||||
if (voltage == SEC_VOLTAGE_18)
|
if (voltage == SEC_VOLTAGE_18)
|
||||||
dm_writel(DM1105_GPIOVAL, lnb_18v);
|
dm1105_gpio_andor(dev,
|
||||||
|
dm1105_boards[dev->boardnr].lnb.mask,
|
||||||
|
dm1105_boards[dev->boardnr].lnb.v18);
|
||||||
else if (voltage == SEC_VOLTAGE_13)
|
else if (voltage == SEC_VOLTAGE_13)
|
||||||
dm_writel(DM1105_GPIOVAL, lnb_13v);
|
dm1105_gpio_andor(dev,
|
||||||
|
dm1105_boards[dev->boardnr].lnb.mask,
|
||||||
|
dm1105_boards[dev->boardnr].lnb.v13);
|
||||||
else
|
else
|
||||||
dm_writel(DM1105_GPIOVAL, lnb_off);
|
dm1105_gpio_andor(dev,
|
||||||
|
dm1105_boards[dev->boardnr].lnb.mask,
|
||||||
|
dm1105_boards[dev->boardnr].lnb.off);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -708,6 +853,38 @@ static int __devinit frontend_init(struct dm1105_dev *dev)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
switch (dev->boardnr) {
|
switch (dev->boardnr) {
|
||||||
|
case DM1105_BOARD_UNBRANDED_I2C_ON_GPIO:
|
||||||
|
dm1105_gpio_enable(dev, GPIO15, 1);
|
||||||
|
dm1105_gpio_clear(dev, GPIO15);
|
||||||
|
msleep(100);
|
||||||
|
dm1105_gpio_set(dev, GPIO15);
|
||||||
|
msleep(200);
|
||||||
|
dev->fe = dvb_attach(
|
||||||
|
stv0299_attach, &sharp_z0194a_config,
|
||||||
|
&dev->i2c_bb_adap);
|
||||||
|
if (dev->fe) {
|
||||||
|
dev->fe->ops.set_voltage = dm1105_set_voltage;
|
||||||
|
dvb_attach(dvb_pll_attach, dev->fe, 0x60,
|
||||||
|
&dev->i2c_bb_adap, DVB_PLL_OPERA1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->fe = dvb_attach(
|
||||||
|
stv0288_attach, &earda_config,
|
||||||
|
&dev->i2c_bb_adap);
|
||||||
|
if (dev->fe) {
|
||||||
|
dev->fe->ops.set_voltage = dm1105_set_voltage;
|
||||||
|
dvb_attach(stb6000_attach, dev->fe, 0x61,
|
||||||
|
&dev->i2c_bb_adap);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->fe = dvb_attach(
|
||||||
|
si21xx_attach, &serit_config,
|
||||||
|
&dev->i2c_bb_adap);
|
||||||
|
if (dev->fe)
|
||||||
|
dev->fe->ops.set_voltage = dm1105_set_voltage;
|
||||||
|
break;
|
||||||
case DM1105_BOARD_DVBWORLD_2004:
|
case DM1105_BOARD_DVBWORLD_2004:
|
||||||
dev->fe = dvb_attach(
|
dev->fe = dvb_attach(
|
||||||
cx24116_attach, &serit_sp2633_config,
|
cx24116_attach, &serit_sp2633_config,
|
||||||
|
@ -870,11 +1047,32 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_dm1105_hw_exit;
|
goto err_dm1105_hw_exit;
|
||||||
|
|
||||||
|
i2c_set_adapdata(&dev->i2c_bb_adap, dev);
|
||||||
|
strcpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME);
|
||||||
|
dev->i2c_bb_adap.owner = THIS_MODULE;
|
||||||
|
dev->i2c_bb_adap.dev.parent = &pdev->dev;
|
||||||
|
dev->i2c_bb_adap.algo_data = &dev->i2c_bit;
|
||||||
|
dev->i2c_bit.data = dev;
|
||||||
|
dev->i2c_bit.setsda = dm1105_setsda;
|
||||||
|
dev->i2c_bit.setscl = dm1105_setscl;
|
||||||
|
dev->i2c_bit.getsda = dm1105_getsda;
|
||||||
|
dev->i2c_bit.getscl = dm1105_getscl;
|
||||||
|
dev->i2c_bit.udelay = 10;
|
||||||
|
dev->i2c_bit.timeout = 10;
|
||||||
|
|
||||||
|
/* Raise SCL and SDA */
|
||||||
|
dm1105_setsda(dev, 1);
|
||||||
|
dm1105_setscl(dev, 1);
|
||||||
|
|
||||||
|
ret = i2c_bit_add_bus(&dev->i2c_bb_adap);
|
||||||
|
if (ret < 0)
|
||||||
|
goto err_i2c_del_adapter;
|
||||||
|
|
||||||
/* dvb */
|
/* dvb */
|
||||||
ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME,
|
ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME,
|
||||||
THIS_MODULE, &pdev->dev, adapter_nr);
|
THIS_MODULE, &pdev->dev, adapter_nr);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_i2c_del_adapter;
|
goto err_i2c_del_adapters;
|
||||||
|
|
||||||
dvb_adapter = &dev->dvb_adapter;
|
dvb_adapter = &dev->dvb_adapter;
|
||||||
|
|
||||||
|
@ -952,6 +1150,8 @@ err_dvb_dmx_release:
|
||||||
dvb_dmx_release(dvbdemux);
|
dvb_dmx_release(dvbdemux);
|
||||||
err_dvb_unregister_adapter:
|
err_dvb_unregister_adapter:
|
||||||
dvb_unregister_adapter(dvb_adapter);
|
dvb_unregister_adapter(dvb_adapter);
|
||||||
|
err_i2c_del_adapters:
|
||||||
|
i2c_del_adapter(&dev->i2c_bb_adap);
|
||||||
err_i2c_del_adapter:
|
err_i2c_del_adapter:
|
||||||
i2c_del_adapter(&dev->i2c_adap);
|
i2c_del_adapter(&dev->i2c_adap);
|
||||||
err_dm1105_hw_exit:
|
err_dm1105_hw_exit:
|
||||||
|
|
|
@ -207,17 +207,6 @@ static int lme2510_stream_restart(struct dvb_usb_device *d)
|
||||||
rbuff, sizeof(rbuff));
|
rbuff, sizeof(rbuff));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u32 keypress)
|
|
||||||
{
|
|
||||||
struct dvb_usb_device *d = adap->dev;
|
|
||||||
|
|
||||||
deb_info(1, "INT Key Keypress =%04x", keypress);
|
|
||||||
|
|
||||||
if (keypress > 0)
|
|
||||||
rc_keydown(d->rc_dev, keypress, 0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out)
|
static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out)
|
||||||
{
|
{
|
||||||
|
@ -256,6 +245,7 @@ static void lme2510_int_response(struct urb *lme_urb)
|
||||||
struct lme2510_state *st = adap->dev->priv;
|
struct lme2510_state *st = adap->dev->priv;
|
||||||
static u8 *ibuf, *rbuf;
|
static u8 *ibuf, *rbuf;
|
||||||
int i = 0, offset;
|
int i = 0, offset;
|
||||||
|
u32 key;
|
||||||
|
|
||||||
switch (lme_urb->status) {
|
switch (lme_urb->status) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -282,10 +272,16 @@ static void lme2510_int_response(struct urb *lme_urb)
|
||||||
|
|
||||||
switch (ibuf[0]) {
|
switch (ibuf[0]) {
|
||||||
case 0xaa:
|
case 0xaa:
|
||||||
debug_data_snipet(1, "INT Remote data snipet in", ibuf);
|
debug_data_snipet(1, "INT Remote data snipet", ibuf);
|
||||||
lme2510_remote_keypress(adap,
|
if ((ibuf[4] + ibuf[5]) == 0xff) {
|
||||||
(u32)(ibuf[2] << 24) + (ibuf[3] << 16) +
|
key = ibuf[5];
|
||||||
(ibuf[4] << 8) + ibuf[5]);
|
key += (ibuf[3] > 0)
|
||||||
|
? (ibuf[3] ^ 0xff) << 8 : 0;
|
||||||
|
key += (ibuf[2] ^ 0xff) << 16;
|
||||||
|
deb_info(1, "INT Key =%08x", key);
|
||||||
|
if (adap->dev->rc_dev != NULL)
|
||||||
|
rc_keydown(adap->dev->rc_dev, key, 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0xbb:
|
case 0xbb:
|
||||||
switch (st->tuner_config) {
|
switch (st->tuner_config) {
|
||||||
|
@ -691,45 +687,6 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||||
return (ret < 0) ? -ENODEV : 0;
|
return (ret < 0) ? -ENODEV : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lme2510_int_service(struct dvb_usb_adapter *adap)
|
|
||||||
{
|
|
||||||
struct dvb_usb_device *d = adap->dev;
|
|
||||||
struct rc_dev *rc;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
info("STA Configuring Remote");
|
|
||||||
|
|
||||||
rc = rc_allocate_device();
|
|
||||||
if (!rc)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
|
|
||||||
strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
|
|
||||||
|
|
||||||
rc->input_name = "LME2510 Remote Control";
|
|
||||||
rc->input_phys = d->rc_phys;
|
|
||||||
rc->map_name = RC_MAP_LME2510;
|
|
||||||
rc->driver_name = "LME 2510";
|
|
||||||
usb_to_input_id(d->udev, &rc->input_id);
|
|
||||||
|
|
||||||
ret = rc_register_device(rc);
|
|
||||||
if (ret) {
|
|
||||||
rc_free_device(rc);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
d->rc_dev = rc;
|
|
||||||
|
|
||||||
/* Start the Interrupt */
|
|
||||||
ret = lme2510_int_read(adap);
|
|
||||||
if (ret < 0) {
|
|
||||||
rc_unregister_device(rc);
|
|
||||||
info("INT Unable to start Interrupt Service");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u8 check_sum(u8 *p, u8 len)
|
static u8 check_sum(u8 *p, u8 len)
|
||||||
{
|
{
|
||||||
u8 sum = 0;
|
u8 sum = 0;
|
||||||
|
@ -831,7 +788,7 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
|
||||||
|
|
||||||
cold_fw = !cold;
|
cold_fw = !cold;
|
||||||
|
|
||||||
if (udev->descriptor.idProduct == 0x1122) {
|
if (le16_to_cpu(udev->descriptor.idProduct) == 0x1122) {
|
||||||
switch (dvb_usb_lme2510_firmware) {
|
switch (dvb_usb_lme2510_firmware) {
|
||||||
default:
|
default:
|
||||||
dvb_usb_lme2510_firmware = TUNER_S0194;
|
dvb_usb_lme2510_firmware = TUNER_S0194;
|
||||||
|
@ -1053,8 +1010,11 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
|
||||||
|
|
||||||
|
|
||||||
end: if (ret) {
|
end: if (ret) {
|
||||||
kfree(adap->fe);
|
if (adap->fe) {
|
||||||
|
dvb_frontend_detach(adap->fe);
|
||||||
adap->fe = NULL;
|
adap->fe = NULL;
|
||||||
|
}
|
||||||
|
adap->dev->props.rc.core.rc_codes = NULL;
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1097,8 +1057,12 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start the Interrupt & Remote*/
|
/* Start the Interrupt*/
|
||||||
ret = lme2510_int_service(adap);
|
ret = lme2510_int_read(adap);
|
||||||
|
if (ret < 0) {
|
||||||
|
info("INT Unable to start Interrupt Service");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1204,6 +1168,12 @@ static struct dvb_usb_device_properties lme2510_properties = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.rc.core = {
|
||||||
|
.protocol = RC_TYPE_NEC,
|
||||||
|
.module_name = "LME2510 Remote Control",
|
||||||
|
.allowed_protos = RC_TYPE_NEC,
|
||||||
|
.rc_codes = RC_MAP_LME2510,
|
||||||
|
},
|
||||||
.power_ctrl = lme2510_powerup,
|
.power_ctrl = lme2510_powerup,
|
||||||
.identify_state = lme2510_identify_state,
|
.identify_state = lme2510_identify_state,
|
||||||
.i2c_algo = &lme2510_i2c_algo,
|
.i2c_algo = &lme2510_i2c_algo,
|
||||||
|
@ -1246,6 +1216,12 @@ static struct dvb_usb_device_properties lme2510c_properties = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.rc.core = {
|
||||||
|
.protocol = RC_TYPE_NEC,
|
||||||
|
.module_name = "LME2510 Remote Control",
|
||||||
|
.allowed_protos = RC_TYPE_NEC,
|
||||||
|
.rc_codes = RC_MAP_LME2510,
|
||||||
|
},
|
||||||
.power_ctrl = lme2510_powerup,
|
.power_ctrl = lme2510_powerup,
|
||||||
.identify_state = lme2510_identify_state,
|
.identify_state = lme2510_identify_state,
|
||||||
.i2c_algo = &lme2510_i2c_algo,
|
.i2c_algo = &lme2510_i2c_algo,
|
||||||
|
@ -1269,19 +1245,21 @@ static void *lme2510_exit_int(struct dvb_usb_device *d)
|
||||||
adap->feedcount = 0;
|
adap->feedcount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->lme_urb != NULL) {
|
if (st->usb_buffer != NULL) {
|
||||||
st->i2c_talk_onoff = 1;
|
st->i2c_talk_onoff = 1;
|
||||||
st->signal_lock = 0;
|
st->signal_lock = 0;
|
||||||
st->signal_level = 0;
|
st->signal_level = 0;
|
||||||
st->signal_sn = 0;
|
st->signal_sn = 0;
|
||||||
buffer = st->usb_buffer;
|
buffer = st->usb_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st->lme_urb != NULL) {
|
||||||
usb_kill_urb(st->lme_urb);
|
usb_kill_urb(st->lme_urb);
|
||||||
usb_free_coherent(d->udev, 5000, st->buffer,
|
usb_free_coherent(d->udev, 5000, st->buffer,
|
||||||
st->lme_urb->transfer_dma);
|
st->lme_urb->transfer_dma);
|
||||||
info("Interrupt Service Stopped");
|
info("Interrupt Service Stopped");
|
||||||
rc_unregister_device(d->rc_dev);
|
|
||||||
info("Remote Stopped");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1293,6 +1271,7 @@ static void lme2510_exit(struct usb_interface *intf)
|
||||||
if (d != NULL) {
|
if (d != NULL) {
|
||||||
usb_buffer = lme2510_exit_int(d);
|
usb_buffer = lme2510_exit_int(d);
|
||||||
dvb_usb_device_exit(intf);
|
dvb_usb_device_exit(intf);
|
||||||
|
if (usb_buffer != NULL)
|
||||||
kfree(usb_buffer);
|
kfree(usb_buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1327,5 +1306,5 @@ module_exit(lme2510_module_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
|
MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
|
||||||
MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
|
MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
|
||||||
MODULE_VERSION("1.86");
|
MODULE_VERSION("1.88");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "stb0899_priv.h"
|
#include "stb0899_priv.h"
|
||||||
#include "stb0899_reg.h"
|
#include "stb0899_reg.h"
|
||||||
|
|
||||||
inline u32 stb0899_do_div(u64 n, u32 d)
|
static inline u32 stb0899_do_div(u64 n, u32 d)
|
||||||
{
|
{
|
||||||
/* wrap do_div() for ease of use */
|
/* wrap do_div() for ease of use */
|
||||||
|
|
||||||
|
|
|
@ -224,7 +224,6 @@ exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(tda8261_attach);
|
EXPORT_SYMBOL(tda8261_attach);
|
||||||
MODULE_PARM_DESC(verbose, "Set verbosity level");
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Manu Abraham");
|
MODULE_AUTHOR("Manu Abraham");
|
||||||
MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner");
|
MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner");
|
||||||
|
|
|
@ -1382,7 +1382,7 @@ static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
|
|
||||||
switch (ctrl->id) {
|
switch (ctrl->id) {
|
||||||
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
|
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
|
||||||
ctrl->val = wl1273_fm_get_tx_ctune(radio);
|
ctrl->cur.val = wl1273_fm_get_tx_ctune(radio);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -191,7 +191,7 @@ static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
|
|
||||||
switch (ctrl->id) {
|
switch (ctrl->id) {
|
||||||
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
|
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
|
||||||
ctrl->val = fm_tx_get_tune_cap_val(fmdev);
|
ctrl->cur.val = fm_tx_get_tune_cap_val(fmdev);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id);
|
fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id);
|
||||||
|
|
|
@ -148,6 +148,18 @@ config IR_ITE_CIR
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called ite-cir.
|
module will be called ite-cir.
|
||||||
|
|
||||||
|
config IR_FINTEK
|
||||||
|
tristate "Fintek Consumer Infrared Transceiver"
|
||||||
|
depends on PNP
|
||||||
|
depends on RC_CORE
|
||||||
|
---help---
|
||||||
|
Say Y here to enable support for integrated infrared receiver
|
||||||
|
/transciever made by Fintek. This chip is found on assorted
|
||||||
|
Jetway motherboards (and of course, possibly others).
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called fintek-cir.
|
||||||
|
|
||||||
config IR_NUVOTON
|
config IR_NUVOTON
|
||||||
tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
|
tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
|
||||||
depends on PNP
|
depends on PNP
|
||||||
|
|
|
@ -16,6 +16,7 @@ obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
|
||||||
obj-$(CONFIG_IR_IMON) += imon.o
|
obj-$(CONFIG_IR_IMON) += imon.o
|
||||||
obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
|
obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
|
||||||
obj-$(CONFIG_IR_MCEUSB) += mceusb.o
|
obj-$(CONFIG_IR_MCEUSB) += mceusb.o
|
||||||
|
obj-$(CONFIG_IR_FINTEK) += fintek-cir.o
|
||||||
obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
|
obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
|
||||||
obj-$(CONFIG_IR_ENE) += ene_ir.o
|
obj-$(CONFIG_IR_ENE) += ene_ir.o
|
||||||
obj-$(CONFIG_IR_REDRAT3) += redrat3.o
|
obj-$(CONFIG_IR_REDRAT3) += redrat3.o
|
||||||
|
|
|
@ -0,0 +1,684 @@
|
||||||
|
/*
|
||||||
|
* Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Jarod Wilson <jarod@redhat.com>
|
||||||
|
*
|
||||||
|
* Special thanks to Fintek for providing hardware and spec sheets.
|
||||||
|
* This driver is based upon the nuvoton, ite and ene drivers for
|
||||||
|
* similar hardware.
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/pnp.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <media/rc-core.h>
|
||||||
|
#include <linux/pci_ids.h>
|
||||||
|
|
||||||
|
#include "fintek-cir.h"
|
||||||
|
|
||||||
|
/* write val to config reg */
|
||||||
|
static inline void fintek_cr_write(struct fintek_dev *fintek, u8 val, u8 reg)
|
||||||
|
{
|
||||||
|
fit_dbg("%s: reg 0x%02x, val 0x%02x (ip/dp: %02x/%02x)",
|
||||||
|
__func__, reg, val, fintek->cr_ip, fintek->cr_dp);
|
||||||
|
outb(reg, fintek->cr_ip);
|
||||||
|
outb(val, fintek->cr_dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read val from config reg */
|
||||||
|
static inline u8 fintek_cr_read(struct fintek_dev *fintek, u8 reg)
|
||||||
|
{
|
||||||
|
u8 val;
|
||||||
|
|
||||||
|
outb(reg, fintek->cr_ip);
|
||||||
|
val = inb(fintek->cr_dp);
|
||||||
|
|
||||||
|
fit_dbg("%s: reg 0x%02x, val 0x%02x (ip/dp: %02x/%02x)",
|
||||||
|
__func__, reg, val, fintek->cr_ip, fintek->cr_dp);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update config register bit without changing other bits */
|
||||||
|
static inline void fintek_set_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg)
|
||||||
|
{
|
||||||
|
u8 tmp = fintek_cr_read(fintek, reg) | val;
|
||||||
|
fintek_cr_write(fintek, tmp, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear config register bit without changing other bits */
|
||||||
|
static inline void fintek_clear_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg)
|
||||||
|
{
|
||||||
|
u8 tmp = fintek_cr_read(fintek, reg) & ~val;
|
||||||
|
fintek_cr_write(fintek, tmp, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enter config mode */
|
||||||
|
static inline void fintek_config_mode_enable(struct fintek_dev *fintek)
|
||||||
|
{
|
||||||
|
/* Enabling Config Mode explicitly requires writing 2x */
|
||||||
|
outb(CONFIG_REG_ENABLE, fintek->cr_ip);
|
||||||
|
outb(CONFIG_REG_ENABLE, fintek->cr_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* exit config mode */
|
||||||
|
static inline void fintek_config_mode_disable(struct fintek_dev *fintek)
|
||||||
|
{
|
||||||
|
outb(CONFIG_REG_DISABLE, fintek->cr_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When you want to address a specific logical device, write its logical
|
||||||
|
* device number to GCR_LOGICAL_DEV_NO
|
||||||
|
*/
|
||||||
|
static inline void fintek_select_logical_dev(struct fintek_dev *fintek, u8 ldev)
|
||||||
|
{
|
||||||
|
fintek_cr_write(fintek, ldev, GCR_LOGICAL_DEV_NO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write val to cir config register */
|
||||||
|
static inline void fintek_cir_reg_write(struct fintek_dev *fintek, u8 val, u8 offset)
|
||||||
|
{
|
||||||
|
outb(val, fintek->cir_addr + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read val from cir config register */
|
||||||
|
static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset)
|
||||||
|
{
|
||||||
|
u8 val;
|
||||||
|
|
||||||
|
val = inb(fintek->cir_addr + offset);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define pr_reg(text, ...) \
|
||||||
|
printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__)
|
||||||
|
|
||||||
|
/* dump current cir register contents */
|
||||||
|
static void cir_dump_regs(struct fintek_dev *fintek)
|
||||||
|
{
|
||||||
|
fintek_config_mode_enable(fintek);
|
||||||
|
fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
|
||||||
|
|
||||||
|
pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME);
|
||||||
|
pr_reg(" * CR CIR BASE ADDR: 0x%x\n",
|
||||||
|
(fintek_cr_read(fintek, CIR_CR_BASE_ADDR_HI) << 8) |
|
||||||
|
fintek_cr_read(fintek, CIR_CR_BASE_ADDR_LO));
|
||||||
|
pr_reg(" * CR CIR IRQ NUM: 0x%x\n",
|
||||||
|
fintek_cr_read(fintek, CIR_CR_IRQ_SEL));
|
||||||
|
|
||||||
|
fintek_config_mode_disable(fintek);
|
||||||
|
|
||||||
|
pr_reg("%s: Dump CIR registers:\n", FINTEK_DRIVER_NAME);
|
||||||
|
pr_reg(" * STATUS: 0x%x\n", fintek_cir_reg_read(fintek, CIR_STATUS));
|
||||||
|
pr_reg(" * CONTROL: 0x%x\n", fintek_cir_reg_read(fintek, CIR_CONTROL));
|
||||||
|
pr_reg(" * RX_DATA: 0x%x\n", fintek_cir_reg_read(fintek, CIR_RX_DATA));
|
||||||
|
pr_reg(" * TX_CONTROL: 0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_CONTROL));
|
||||||
|
pr_reg(" * TX_DATA: 0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_DATA));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* detect hardware features */
|
||||||
|
static int fintek_hw_detect(struct fintek_dev *fintek)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
u8 chip_major, chip_minor;
|
||||||
|
u8 vendor_major, vendor_minor;
|
||||||
|
u8 portsel, ir_class;
|
||||||
|
u16 vendor;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
fintek_config_mode_enable(fintek);
|
||||||
|
|
||||||
|
/* Check if we're using config port 0x4e or 0x2e */
|
||||||
|
portsel = fintek_cr_read(fintek, GCR_CONFIG_PORT_SEL);
|
||||||
|
if (portsel == 0xff) {
|
||||||
|
fit_pr(KERN_INFO, "first portsel read was bunk, trying alt");
|
||||||
|
fintek_config_mode_disable(fintek);
|
||||||
|
fintek->cr_ip = CR_INDEX_PORT2;
|
||||||
|
fintek->cr_dp = CR_DATA_PORT2;
|
||||||
|
fintek_config_mode_enable(fintek);
|
||||||
|
portsel = fintek_cr_read(fintek, GCR_CONFIG_PORT_SEL);
|
||||||
|
}
|
||||||
|
fit_dbg("portsel reg: 0x%02x", portsel);
|
||||||
|
|
||||||
|
ir_class = fintek_cir_reg_read(fintek, CIR_CR_CLASS);
|
||||||
|
fit_dbg("ir_class reg: 0x%02x", ir_class);
|
||||||
|
|
||||||
|
switch (ir_class) {
|
||||||
|
case CLASS_RX_2TX:
|
||||||
|
case CLASS_RX_1TX:
|
||||||
|
fintek->hw_tx_capable = true;
|
||||||
|
break;
|
||||||
|
case CLASS_RX_ONLY:
|
||||||
|
default:
|
||||||
|
fintek->hw_tx_capable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI);
|
||||||
|
chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO);
|
||||||
|
|
||||||
|
vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI);
|
||||||
|
vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO);
|
||||||
|
vendor = vendor_major << 8 | vendor_minor;
|
||||||
|
|
||||||
|
if (vendor != VENDOR_ID_FINTEK)
|
||||||
|
fit_pr(KERN_WARNING, "Unknown vendor ID: 0x%04x", vendor);
|
||||||
|
else
|
||||||
|
fit_dbg("Read Fintek vendor ID from chip");
|
||||||
|
|
||||||
|
fintek_config_mode_disable(fintek);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&fintek->fintek_lock, flags);
|
||||||
|
fintek->chip_major = chip_major;
|
||||||
|
fintek->chip_minor = chip_minor;
|
||||||
|
fintek->chip_vendor = vendor;
|
||||||
|
spin_unlock_irqrestore(&fintek->fintek_lock, flags);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fintek_cir_ldev_init(struct fintek_dev *fintek)
|
||||||
|
{
|
||||||
|
/* Select CIR logical device and enable */
|
||||||
|
fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
|
||||||
|
fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
|
||||||
|
|
||||||
|
/* Write allocated CIR address and IRQ information to hardware */
|
||||||
|
fintek_cr_write(fintek, fintek->cir_addr >> 8, CIR_CR_BASE_ADDR_HI);
|
||||||
|
fintek_cr_write(fintek, fintek->cir_addr & 0xff, CIR_CR_BASE_ADDR_LO);
|
||||||
|
|
||||||
|
fintek_cr_write(fintek, fintek->cir_irq, CIR_CR_IRQ_SEL);
|
||||||
|
|
||||||
|
fit_dbg("CIR initialized, base io address: 0x%lx, irq: %d (len: %d)",
|
||||||
|
fintek->cir_addr, fintek->cir_irq, fintek->cir_port_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable CIR interrupts */
|
||||||
|
static void fintek_enable_cir_irq(struct fintek_dev *fintek)
|
||||||
|
{
|
||||||
|
fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_EN, CIR_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fintek_cir_regs_init(struct fintek_dev *fintek)
|
||||||
|
{
|
||||||
|
/* clear any and all stray interrupts */
|
||||||
|
fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
|
||||||
|
|
||||||
|
/* and finally, enable interrupts */
|
||||||
|
fintek_enable_cir_irq(fintek);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fintek_enable_wake(struct fintek_dev *fintek)
|
||||||
|
{
|
||||||
|
fintek_config_mode_enable(fintek);
|
||||||
|
fintek_select_logical_dev(fintek, LOGICAL_DEV_ACPI);
|
||||||
|
|
||||||
|
/* Allow CIR PME's to wake system */
|
||||||
|
fintek_set_reg_bit(fintek, ACPI_WAKE_EN_CIR_BIT, LDEV_ACPI_WAKE_EN_REG);
|
||||||
|
/* Enable CIR PME's */
|
||||||
|
fintek_set_reg_bit(fintek, ACPI_PME_CIR_BIT, LDEV_ACPI_PME_EN_REG);
|
||||||
|
/* Clear CIR PME status register */
|
||||||
|
fintek_set_reg_bit(fintek, ACPI_PME_CIR_BIT, LDEV_ACPI_PME_CLR_REG);
|
||||||
|
/* Save state */
|
||||||
|
fintek_set_reg_bit(fintek, ACPI_STATE_CIR_BIT, LDEV_ACPI_STATE_REG);
|
||||||
|
|
||||||
|
fintek_config_mode_disable(fintek);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fintek_cmdsize(u8 cmd, u8 subcmd)
|
||||||
|
{
|
||||||
|
int datasize = 0;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case BUF_COMMAND_NULL:
|
||||||
|
if (subcmd == BUF_HW_CMD_HEADER)
|
||||||
|
datasize = 1;
|
||||||
|
break;
|
||||||
|
case BUF_HW_CMD_HEADER:
|
||||||
|
if (subcmd == BUF_CMD_G_REVISION)
|
||||||
|
datasize = 2;
|
||||||
|
break;
|
||||||
|
case BUF_COMMAND_HEADER:
|
||||||
|
switch (subcmd) {
|
||||||
|
case BUF_CMD_S_CARRIER:
|
||||||
|
case BUF_CMD_S_TIMEOUT:
|
||||||
|
case BUF_RSP_PULSE_COUNT:
|
||||||
|
datasize = 2;
|
||||||
|
break;
|
||||||
|
case BUF_CMD_SIG_END:
|
||||||
|
case BUF_CMD_S_TXMASK:
|
||||||
|
case BUF_CMD_S_RXSENSOR:
|
||||||
|
datasize = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return datasize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process ir data stored in driver buffer */
|
||||||
|
static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
|
||||||
|
{
|
||||||
|
DEFINE_IR_RAW_EVENT(rawir);
|
||||||
|
u8 sample;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < fintek->pkts; i++) {
|
||||||
|
sample = fintek->buf[i];
|
||||||
|
switch (fintek->parser_state) {
|
||||||
|
case CMD_HEADER:
|
||||||
|
fintek->cmd = sample;
|
||||||
|
if ((fintek->cmd == BUF_COMMAND_HEADER) ||
|
||||||
|
((fintek->cmd & BUF_COMMAND_MASK) !=
|
||||||
|
BUF_PULSE_BIT)) {
|
||||||
|
fintek->parser_state = SUBCMD;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fintek->rem = (fintek->cmd & BUF_LEN_MASK);
|
||||||
|
fit_dbg("%s: rem: 0x%02x", __func__, fintek->rem);
|
||||||
|
if (fintek->rem)
|
||||||
|
fintek->parser_state = PARSE_IRDATA;
|
||||||
|
else
|
||||||
|
ir_raw_event_reset(fintek->rdev);
|
||||||
|
break;
|
||||||
|
case SUBCMD:
|
||||||
|
fintek->rem = fintek_cmdsize(fintek->cmd, sample);
|
||||||
|
fintek->parser_state = CMD_DATA;
|
||||||
|
break;
|
||||||
|
case CMD_DATA:
|
||||||
|
fintek->rem--;
|
||||||
|
break;
|
||||||
|
case PARSE_IRDATA:
|
||||||
|
fintek->rem--;
|
||||||
|
init_ir_raw_event(&rawir);
|
||||||
|
rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
|
||||||
|
rawir.duration = US_TO_NS((sample & BUF_SAMPLE_MASK)
|
||||||
|
* CIR_SAMPLE_PERIOD);
|
||||||
|
|
||||||
|
fit_dbg("Storing %s with duration %d",
|
||||||
|
rawir.pulse ? "pulse" : "space",
|
||||||
|
rawir.duration);
|
||||||
|
ir_raw_event_store_with_filter(fintek->rdev, &rawir);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fintek->parser_state != CMD_HEADER) && !fintek->rem)
|
||||||
|
fintek->parser_state = CMD_HEADER;
|
||||||
|
}
|
||||||
|
|
||||||
|
fintek->pkts = 0;
|
||||||
|
|
||||||
|
fit_dbg("Calling ir_raw_event_handle");
|
||||||
|
ir_raw_event_handle(fintek->rdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy data from hardware rx register into driver buffer */
|
||||||
|
static void fintek_get_rx_ir_data(struct fintek_dev *fintek, u8 rx_irqs)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
u8 sample, status;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&fintek->fintek_lock, flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We must read data from CIR_RX_DATA until the hardware IR buffer
|
||||||
|
* is empty and clears the RX_TIMEOUT and/or RX_RECEIVE flags in
|
||||||
|
* the CIR_STATUS register
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
sample = fintek_cir_reg_read(fintek, CIR_RX_DATA);
|
||||||
|
fit_dbg("%s: sample: 0x%02x", __func__, sample);
|
||||||
|
|
||||||
|
fintek->buf[fintek->pkts] = sample;
|
||||||
|
fintek->pkts++;
|
||||||
|
|
||||||
|
status = fintek_cir_reg_read(fintek, CIR_STATUS);
|
||||||
|
if (!(status & CIR_STATUS_IRQ_EN))
|
||||||
|
break;
|
||||||
|
} while (status & rx_irqs);
|
||||||
|
|
||||||
|
fintek_process_rx_ir_data(fintek);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&fintek->fintek_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fintek_cir_log_irqs(u8 status)
|
||||||
|
{
|
||||||
|
fit_pr(KERN_INFO, "IRQ 0x%02x:%s%s%s%s%s", status,
|
||||||
|
status & CIR_STATUS_IRQ_EN ? " IRQEN" : "",
|
||||||
|
status & CIR_STATUS_TX_FINISH ? " TXF" : "",
|
||||||
|
status & CIR_STATUS_TX_UNDERRUN ? " TXU" : "",
|
||||||
|
status & CIR_STATUS_RX_TIMEOUT ? " RXTO" : "",
|
||||||
|
status & CIR_STATUS_RX_RECEIVE ? " RXOK" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* interrupt service routine for incoming and outgoing CIR data */
|
||||||
|
static irqreturn_t fintek_cir_isr(int irq, void *data)
|
||||||
|
{
|
||||||
|
struct fintek_dev *fintek = data;
|
||||||
|
u8 status, rx_irqs;
|
||||||
|
|
||||||
|
fit_dbg_verbose("%s firing", __func__);
|
||||||
|
|
||||||
|
fintek_config_mode_enable(fintek);
|
||||||
|
fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
|
||||||
|
fintek_config_mode_disable(fintek);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get IR Status register contents. Write 1 to ack/clear
|
||||||
|
*
|
||||||
|
* bit: reg name - description
|
||||||
|
* 3: TX_FINISH - TX is finished
|
||||||
|
* 2: TX_UNDERRUN - TX underrun
|
||||||
|
* 1: RX_TIMEOUT - RX data timeout
|
||||||
|
* 0: RX_RECEIVE - RX data received
|
||||||
|
*/
|
||||||
|
status = fintek_cir_reg_read(fintek, CIR_STATUS);
|
||||||
|
if (!(status & CIR_STATUS_IRQ_MASK) || status == 0xff) {
|
||||||
|
fit_dbg_verbose("%s exiting, IRSTS 0x%02x", __func__, status);
|
||||||
|
fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
|
||||||
|
return IRQ_RETVAL(IRQ_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
fintek_cir_log_irqs(status);
|
||||||
|
|
||||||
|
rx_irqs = status & (CIR_STATUS_RX_RECEIVE | CIR_STATUS_RX_TIMEOUT);
|
||||||
|
if (rx_irqs)
|
||||||
|
fintek_get_rx_ir_data(fintek, rx_irqs);
|
||||||
|
|
||||||
|
/* ack/clear all irq flags we've got */
|
||||||
|
fintek_cir_reg_write(fintek, status, CIR_STATUS);
|
||||||
|
|
||||||
|
fit_dbg_verbose("%s done", __func__);
|
||||||
|
return IRQ_RETVAL(IRQ_HANDLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fintek_enable_cir(struct fintek_dev *fintek)
|
||||||
|
{
|
||||||
|
/* set IRQ enabled */
|
||||||
|
fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_EN, CIR_STATUS);
|
||||||
|
|
||||||
|
fintek_config_mode_enable(fintek);
|
||||||
|
|
||||||
|
/* enable the CIR logical device */
|
||||||
|
fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
|
||||||
|
fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
|
||||||
|
|
||||||
|
fintek_config_mode_disable(fintek);
|
||||||
|
|
||||||
|
/* clear all pending interrupts */
|
||||||
|
fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
|
||||||
|
|
||||||
|
/* enable interrupts */
|
||||||
|
fintek_enable_cir_irq(fintek);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fintek_disable_cir(struct fintek_dev *fintek)
|
||||||
|
{
|
||||||
|
fintek_config_mode_enable(fintek);
|
||||||
|
|
||||||
|
/* disable the CIR logical device */
|
||||||
|
fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
|
||||||
|
fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
|
||||||
|
|
||||||
|
fintek_config_mode_disable(fintek);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fintek_open(struct rc_dev *dev)
|
||||||
|
{
|
||||||
|
struct fintek_dev *fintek = dev->priv;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&fintek->fintek_lock, flags);
|
||||||
|
fintek_enable_cir(fintek);
|
||||||
|
spin_unlock_irqrestore(&fintek->fintek_lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fintek_close(struct rc_dev *dev)
|
||||||
|
{
|
||||||
|
struct fintek_dev *fintek = dev->priv;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&fintek->fintek_lock, flags);
|
||||||
|
fintek_disable_cir(fintek);
|
||||||
|
spin_unlock_irqrestore(&fintek->fintek_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate memory, probe hardware, and initialize everything */
|
||||||
|
static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
|
||||||
|
{
|
||||||
|
struct fintek_dev *fintek;
|
||||||
|
struct rc_dev *rdev;
|
||||||
|
int ret = -ENOMEM;
|
||||||
|
|
||||||
|
fintek = kzalloc(sizeof(struct fintek_dev), GFP_KERNEL);
|
||||||
|
if (!fintek)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* input device for IR remote (and tx) */
|
||||||
|
rdev = rc_allocate_device();
|
||||||
|
if (!rdev)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
ret = -ENODEV;
|
||||||
|
/* validate pnp resources */
|
||||||
|
if (!pnp_port_valid(pdev, 0)) {
|
||||||
|
dev_err(&pdev->dev, "IR PNP Port not valid!\n");
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pnp_irq_valid(pdev, 0)) {
|
||||||
|
dev_err(&pdev->dev, "IR PNP IRQ not valid!\n");
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
fintek->cir_addr = pnp_port_start(pdev, 0);
|
||||||
|
fintek->cir_irq = pnp_irq(pdev, 0);
|
||||||
|
fintek->cir_port_len = pnp_port_len(pdev, 0);
|
||||||
|
|
||||||
|
fintek->cr_ip = CR_INDEX_PORT;
|
||||||
|
fintek->cr_dp = CR_DATA_PORT;
|
||||||
|
|
||||||
|
spin_lock_init(&fintek->fintek_lock);
|
||||||
|
|
||||||
|
ret = -EBUSY;
|
||||||
|
/* now claim resources */
|
||||||
|
if (!request_region(fintek->cir_addr,
|
||||||
|
fintek->cir_port_len, FINTEK_DRIVER_NAME))
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
if (request_irq(fintek->cir_irq, fintek_cir_isr, IRQF_SHARED,
|
||||||
|
FINTEK_DRIVER_NAME, (void *)fintek))
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
pnp_set_drvdata(pdev, fintek);
|
||||||
|
fintek->pdev = pdev;
|
||||||
|
|
||||||
|
ret = fintek_hw_detect(fintek);
|
||||||
|
if (ret)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
/* Initialize CIR & CIR Wake Logical Devices */
|
||||||
|
fintek_config_mode_enable(fintek);
|
||||||
|
fintek_cir_ldev_init(fintek);
|
||||||
|
fintek_config_mode_disable(fintek);
|
||||||
|
|
||||||
|
/* Initialize CIR & CIR Wake Config Registers */
|
||||||
|
fintek_cir_regs_init(fintek);
|
||||||
|
|
||||||
|
/* Set up the rc device */
|
||||||
|
rdev->priv = fintek;
|
||||||
|
rdev->driver_type = RC_DRIVER_IR_RAW;
|
||||||
|
rdev->allowed_protos = RC_TYPE_ALL;
|
||||||
|
rdev->open = fintek_open;
|
||||||
|
rdev->close = fintek_close;
|
||||||
|
rdev->input_name = FINTEK_DESCRIPTION;
|
||||||
|
rdev->input_phys = "fintek/cir0";
|
||||||
|
rdev->input_id.bustype = BUS_HOST;
|
||||||
|
rdev->input_id.vendor = VENDOR_ID_FINTEK;
|
||||||
|
rdev->input_id.product = fintek->chip_major;
|
||||||
|
rdev->input_id.version = fintek->chip_minor;
|
||||||
|
rdev->dev.parent = &pdev->dev;
|
||||||
|
rdev->driver_name = FINTEK_DRIVER_NAME;
|
||||||
|
rdev->map_name = RC_MAP_RC6_MCE;
|
||||||
|
rdev->timeout = US_TO_NS(1000);
|
||||||
|
/* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
|
||||||
|
rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD);
|
||||||
|
|
||||||
|
ret = rc_register_device(rdev);
|
||||||
|
if (ret)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
device_init_wakeup(&pdev->dev, true);
|
||||||
|
fintek->rdev = rdev;
|
||||||
|
fit_pr(KERN_NOTICE, "driver has been successfully loaded\n");
|
||||||
|
if (debug)
|
||||||
|
cir_dump_regs(fintek);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
if (fintek->cir_irq)
|
||||||
|
free_irq(fintek->cir_irq, fintek);
|
||||||
|
if (fintek->cir_addr)
|
||||||
|
release_region(fintek->cir_addr, fintek->cir_port_len);
|
||||||
|
|
||||||
|
rc_free_device(rdev);
|
||||||
|
kfree(fintek);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __devexit fintek_remove(struct pnp_dev *pdev)
|
||||||
|
{
|
||||||
|
struct fintek_dev *fintek = pnp_get_drvdata(pdev);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&fintek->fintek_lock, flags);
|
||||||
|
/* disable CIR */
|
||||||
|
fintek_disable_cir(fintek);
|
||||||
|
fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
|
||||||
|
/* enable CIR Wake (for IR power-on) */
|
||||||
|
fintek_enable_wake(fintek);
|
||||||
|
spin_unlock_irqrestore(&fintek->fintek_lock, flags);
|
||||||
|
|
||||||
|
/* free resources */
|
||||||
|
free_irq(fintek->cir_irq, fintek);
|
||||||
|
release_region(fintek->cir_addr, fintek->cir_port_len);
|
||||||
|
|
||||||
|
rc_unregister_device(fintek->rdev);
|
||||||
|
|
||||||
|
kfree(fintek);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state)
|
||||||
|
{
|
||||||
|
struct fintek_dev *fintek = pnp_get_drvdata(pdev);
|
||||||
|
|
||||||
|
fit_dbg("%s called", __func__);
|
||||||
|
|
||||||
|
/* disable all CIR interrupts */
|
||||||
|
fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
|
||||||
|
|
||||||
|
fintek_config_mode_enable(fintek);
|
||||||
|
|
||||||
|
/* disable cir logical dev */
|
||||||
|
fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
|
||||||
|
fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
|
||||||
|
|
||||||
|
fintek_config_mode_disable(fintek);
|
||||||
|
|
||||||
|
/* make sure wake is enabled */
|
||||||
|
fintek_enable_wake(fintek);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fintek_resume(struct pnp_dev *pdev)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct fintek_dev *fintek = pnp_get_drvdata(pdev);
|
||||||
|
|
||||||
|
fit_dbg("%s called", __func__);
|
||||||
|
|
||||||
|
/* open interrupt */
|
||||||
|
fintek_enable_cir_irq(fintek);
|
||||||
|
|
||||||
|
/* Enable CIR logical device */
|
||||||
|
fintek_config_mode_enable(fintek);
|
||||||
|
fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
|
||||||
|
fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
|
||||||
|
|
||||||
|
fintek_config_mode_disable(fintek);
|
||||||
|
|
||||||
|
fintek_cir_regs_init(fintek);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fintek_shutdown(struct pnp_dev *pdev)
|
||||||
|
{
|
||||||
|
struct fintek_dev *fintek = pnp_get_drvdata(pdev);
|
||||||
|
fintek_enable_wake(fintek);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pnp_device_id fintek_ids[] = {
|
||||||
|
{ "FIT0002", 0 }, /* CIR */
|
||||||
|
{ "", 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pnp_driver fintek_driver = {
|
||||||
|
.name = FINTEK_DRIVER_NAME,
|
||||||
|
.id_table = fintek_ids,
|
||||||
|
.flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
|
||||||
|
.probe = fintek_probe,
|
||||||
|
.remove = __devexit_p(fintek_remove),
|
||||||
|
.suspend = fintek_suspend,
|
||||||
|
.resume = fintek_resume,
|
||||||
|
.shutdown = fintek_shutdown,
|
||||||
|
};
|
||||||
|
|
||||||
|
int fintek_init(void)
|
||||||
|
{
|
||||||
|
return pnp_register_driver(&fintek_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fintek_exit(void)
|
||||||
|
{
|
||||||
|
pnp_unregister_driver(&fintek_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_param(debug, int, S_IRUGO | S_IWUSR);
|
||||||
|
MODULE_PARM_DESC(debug, "Enable debugging output");
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(pnp, fintek_ids);
|
||||||
|
MODULE_DESCRIPTION(FINTEK_DESCRIPTION " driver");
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
module_init(fintek_init);
|
||||||
|
module_exit(fintek_exit);
|
|
@ -0,0 +1,243 @@
|
||||||
|
/*
|
||||||
|
* Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Jarod Wilson <jarod@redhat.com>
|
||||||
|
*
|
||||||
|
* Special thanks to Fintek for providing hardware and spec sheets.
|
||||||
|
* This driver is based upon the nuvoton, ite and ene drivers for
|
||||||
|
* similar hardware.
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
* USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
|
||||||
|
/* platform driver name to register */
|
||||||
|
#define FINTEK_DRIVER_NAME "fintek-cir"
|
||||||
|
#define FINTEK_DESCRIPTION "Fintek LPC SuperIO Consumer IR Transceiver"
|
||||||
|
#define VENDOR_ID_FINTEK 0x1934
|
||||||
|
|
||||||
|
|
||||||
|
/* debugging module parameter */
|
||||||
|
static int debug;
|
||||||
|
|
||||||
|
#define fit_pr(level, text, ...) \
|
||||||
|
printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__)
|
||||||
|
|
||||||
|
#define fit_dbg(text, ...) \
|
||||||
|
if (debug) \
|
||||||
|
printk(KERN_DEBUG \
|
||||||
|
KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
|
||||||
|
|
||||||
|
#define fit_dbg_verbose(text, ...) \
|
||||||
|
if (debug > 1) \
|
||||||
|
printk(KERN_DEBUG \
|
||||||
|
KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
|
||||||
|
|
||||||
|
#define fit_dbg_wake(text, ...) \
|
||||||
|
if (debug > 2) \
|
||||||
|
printk(KERN_DEBUG \
|
||||||
|
KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
|
||||||
|
|
||||||
|
|
||||||
|
#define TX_BUF_LEN 256
|
||||||
|
#define RX_BUF_LEN 32
|
||||||
|
|
||||||
|
struct fintek_dev {
|
||||||
|
struct pnp_dev *pdev;
|
||||||
|
struct rc_dev *rdev;
|
||||||
|
|
||||||
|
spinlock_t fintek_lock;
|
||||||
|
|
||||||
|
/* for rx */
|
||||||
|
u8 buf[RX_BUF_LEN];
|
||||||
|
unsigned int pkts;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
spinlock_t lock;
|
||||||
|
u8 buf[TX_BUF_LEN];
|
||||||
|
unsigned int buf_count;
|
||||||
|
unsigned int cur_buf_num;
|
||||||
|
wait_queue_head_t queue;
|
||||||
|
} tx;
|
||||||
|
|
||||||
|
/* Config register index/data port pair */
|
||||||
|
u8 cr_ip;
|
||||||
|
u8 cr_dp;
|
||||||
|
|
||||||
|
/* hardware I/O settings */
|
||||||
|
unsigned long cir_addr;
|
||||||
|
int cir_irq;
|
||||||
|
int cir_port_len;
|
||||||
|
|
||||||
|
/* hardware id */
|
||||||
|
u8 chip_major;
|
||||||
|
u8 chip_minor;
|
||||||
|
u16 chip_vendor;
|
||||||
|
|
||||||
|
/* hardware features */
|
||||||
|
bool hw_learning_capable;
|
||||||
|
bool hw_tx_capable;
|
||||||
|
|
||||||
|
/* rx settings */
|
||||||
|
bool learning_enabled;
|
||||||
|
bool carrier_detect_enabled;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CMD_HEADER = 0,
|
||||||
|
SUBCMD,
|
||||||
|
CMD_DATA,
|
||||||
|
PARSE_IRDATA,
|
||||||
|
} parser_state;
|
||||||
|
|
||||||
|
u8 cmd, rem;
|
||||||
|
|
||||||
|
/* carrier period = 1 / frequency */
|
||||||
|
u32 carrier;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* buffer packet constants, largely identical to mceusb.c */
|
||||||
|
#define BUF_PULSE_BIT 0x80
|
||||||
|
#define BUF_LEN_MASK 0x1f
|
||||||
|
#define BUF_SAMPLE_MASK 0x7f
|
||||||
|
|
||||||
|
#define BUF_COMMAND_HEADER 0x9f
|
||||||
|
#define BUF_COMMAND_MASK 0xe0
|
||||||
|
#define BUF_COMMAND_NULL 0x00
|
||||||
|
#define BUF_HW_CMD_HEADER 0xff
|
||||||
|
#define BUF_CMD_G_REVISION 0x0b
|
||||||
|
#define BUF_CMD_S_CARRIER 0x06
|
||||||
|
#define BUF_CMD_S_TIMEOUT 0x0c
|
||||||
|
#define BUF_CMD_SIG_END 0x01
|
||||||
|
#define BUF_CMD_S_TXMASK 0x08
|
||||||
|
#define BUF_CMD_S_RXSENSOR 0x14
|
||||||
|
#define BUF_RSP_PULSE_COUNT 0x15
|
||||||
|
|
||||||
|
#define CIR_SAMPLE_PERIOD 50
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configuration Register:
|
||||||
|
* Index Port
|
||||||
|
* Data Port
|
||||||
|
*/
|
||||||
|
#define CR_INDEX_PORT 0x2e
|
||||||
|
#define CR_DATA_PORT 0x2f
|
||||||
|
|
||||||
|
/* Possible alternate values, depends on how the chip is wired */
|
||||||
|
#define CR_INDEX_PORT2 0x4e
|
||||||
|
#define CR_DATA_PORT2 0x4f
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GCR_CONFIG_PORT_SEL bit 4 specifies which Index Port value is
|
||||||
|
* active. 1 = 0x4e, 0 = 0x2e
|
||||||
|
*/
|
||||||
|
#define PORT_SEL_PORT_4E_EN 0x10
|
||||||
|
|
||||||
|
/* Extended Function Mode enable/disable magic values */
|
||||||
|
#define CONFIG_REG_ENABLE 0x87
|
||||||
|
#define CONFIG_REG_DISABLE 0xaa
|
||||||
|
|
||||||
|
/* Chip IDs found in CR_CHIP_ID_{HI,LO} */
|
||||||
|
#define CHIP_ID_HIGH_F71809U 0x04
|
||||||
|
#define CHIP_ID_LOW_F71809U 0x08
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global control regs we need to care about:
|
||||||
|
* Global Control def.
|
||||||
|
* Register name addr val. */
|
||||||
|
#define GCR_SOFTWARE_RESET 0x02 /* 0x00 */
|
||||||
|
#define GCR_LOGICAL_DEV_NO 0x07 /* 0x00 */
|
||||||
|
#define GCR_CHIP_ID_HI 0x20 /* 0x04 */
|
||||||
|
#define GCR_CHIP_ID_LO 0x21 /* 0x08 */
|
||||||
|
#define GCR_VENDOR_ID_HI 0x23 /* 0x19 */
|
||||||
|
#define GCR_VENDOR_ID_LO 0x24 /* 0x34 */
|
||||||
|
#define GCR_CONFIG_PORT_SEL 0x25 /* 0x01 */
|
||||||
|
#define GCR_KBMOUSE_WAKEUP 0x27
|
||||||
|
|
||||||
|
#define LOGICAL_DEV_DISABLE 0x00
|
||||||
|
#define LOGICAL_DEV_ENABLE 0x01
|
||||||
|
|
||||||
|
/* Logical device number of the CIR function */
|
||||||
|
#define LOGICAL_DEV_CIR 0x05
|
||||||
|
|
||||||
|
/* CIR Logical Device (LDN 0x08) config registers */
|
||||||
|
#define CIR_CR_COMMAND_INDEX 0x04
|
||||||
|
#define CIR_CR_IRCS 0x05 /* Before host writes command to IR, host
|
||||||
|
must set to 1. When host finshes write
|
||||||
|
command to IR, host must clear to 0. */
|
||||||
|
#define CIR_CR_COMMAND_DATA 0x06 /* Host read or write comand data */
|
||||||
|
#define CIR_CR_CLASS 0x07 /* 0xff = rx-only, 0x66 = rx + 2 tx,
|
||||||
|
0x33 = rx + 1 tx */
|
||||||
|
#define CIR_CR_DEV_EN 0x30 /* bit0 = 1 enables CIR */
|
||||||
|
#define CIR_CR_BASE_ADDR_HI 0x60 /* MSB of CIR IO base addr */
|
||||||
|
#define CIR_CR_BASE_ADDR_LO 0x61 /* LSB of CIR IO base addr */
|
||||||
|
#define CIR_CR_IRQ_SEL 0x70 /* bits3-0 store CIR IRQ */
|
||||||
|
#define CIR_CR_PSOUT_STATUS 0xf1
|
||||||
|
#define CIR_CR_WAKE_KEY3_ADDR 0xf8
|
||||||
|
#define CIR_CR_WAKE_KEY3_CODE 0xf9
|
||||||
|
#define CIR_CR_WAKE_KEY3_DC 0xfa
|
||||||
|
#define CIR_CR_WAKE_CONTROL 0xfb
|
||||||
|
#define CIR_CR_WAKE_KEY12_ADDR 0xfc
|
||||||
|
#define CIR_CR_WAKE_KEY4_ADDR 0xfd
|
||||||
|
#define CIR_CR_WAKE_KEY5_ADDR 0xfe
|
||||||
|
|
||||||
|
#define CLASS_RX_ONLY 0xff
|
||||||
|
#define CLASS_RX_2TX 0x66
|
||||||
|
#define CLASS_RX_1TX 0x33
|
||||||
|
|
||||||
|
/* CIR device registers */
|
||||||
|
#define CIR_STATUS 0x00
|
||||||
|
#define CIR_RX_DATA 0x01
|
||||||
|
#define CIR_TX_CONTROL 0x02
|
||||||
|
#define CIR_TX_DATA 0x03
|
||||||
|
#define CIR_CONTROL 0x04
|
||||||
|
|
||||||
|
/* Bits to enable CIR wake */
|
||||||
|
#define LOGICAL_DEV_ACPI 0x01
|
||||||
|
#define LDEV_ACPI_WAKE_EN_REG 0xe8
|
||||||
|
#define ACPI_WAKE_EN_CIR_BIT 0x04
|
||||||
|
|
||||||
|
#define LDEV_ACPI_PME_EN_REG 0xf0
|
||||||
|
#define LDEV_ACPI_PME_CLR_REG 0xf1
|
||||||
|
#define ACPI_PME_CIR_BIT 0x02
|
||||||
|
|
||||||
|
#define LDEV_ACPI_STATE_REG 0xf4
|
||||||
|
#define ACPI_STATE_CIR_BIT 0x20
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CIR status register (0x00):
|
||||||
|
* 7 - CIR_IRQ_EN (1 = enable CIR IRQ, 0 = disable)
|
||||||
|
* 3 - TX_FINISH (1 when TX finished, write 1 to clear)
|
||||||
|
* 2 - TX_UNDERRUN (1 on TX underrun, write 1 to clear)
|
||||||
|
* 1 - RX_TIMEOUT (1 on RX timeout, write 1 to clear)
|
||||||
|
* 0 - RX_RECEIVE (1 on RX receive, write 1 to clear)
|
||||||
|
*/
|
||||||
|
#define CIR_STATUS_IRQ_EN 0x80
|
||||||
|
#define CIR_STATUS_TX_FINISH 0x08
|
||||||
|
#define CIR_STATUS_TX_UNDERRUN 0x04
|
||||||
|
#define CIR_STATUS_RX_TIMEOUT 0x02
|
||||||
|
#define CIR_STATUS_RX_RECEIVE 0x01
|
||||||
|
#define CIR_STATUS_IRQ_MASK 0x0f
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CIR TX control register (0x02):
|
||||||
|
* 7 - TX_START (1 to indicate TX start, auto-cleared when done)
|
||||||
|
* 6 - TX_END (1 to indicate TX data written to TX fifo)
|
||||||
|
*/
|
||||||
|
#define CIR_TX_CONTROL_TX_START 0x80
|
||||||
|
#define CIR_TX_CONTROL_TX_END 0x40
|
||||||
|
|
|
@ -14,81 +14,81 @@
|
||||||
|
|
||||||
static struct rc_map_table lme2510_rc[] = {
|
static struct rc_map_table lme2510_rc[] = {
|
||||||
/* Type 1 - 26 buttons */
|
/* Type 1 - 26 buttons */
|
||||||
{ 0xef12ba45, KEY_0 },
|
{ 0x10ed45, KEY_0 },
|
||||||
{ 0xef12a05f, KEY_1 },
|
{ 0x10ed5f, KEY_1 },
|
||||||
{ 0xef12af50, KEY_2 },
|
{ 0x10ed50, KEY_2 },
|
||||||
{ 0xef12a25d, KEY_3 },
|
{ 0x10ed5d, KEY_3 },
|
||||||
{ 0xef12be41, KEY_4 },
|
{ 0x10ed41, KEY_4 },
|
||||||
{ 0xef12f50a, KEY_5 },
|
{ 0x10ed0a, KEY_5 },
|
||||||
{ 0xef12bd42, KEY_6 },
|
{ 0x10ed42, KEY_6 },
|
||||||
{ 0xef12b847, KEY_7 },
|
{ 0x10ed47, KEY_7 },
|
||||||
{ 0xef12b649, KEY_8 },
|
{ 0x10ed49, KEY_8 },
|
||||||
{ 0xef12fa05, KEY_9 },
|
{ 0x10ed05, KEY_9 },
|
||||||
{ 0xef12bc43, KEY_POWER },
|
{ 0x10ed43, KEY_POWER },
|
||||||
{ 0xef12b946, KEY_SUBTITLE },
|
{ 0x10ed46, KEY_SUBTITLE },
|
||||||
{ 0xef12f906, KEY_PAUSE },
|
{ 0x10ed06, KEY_PAUSE },
|
||||||
{ 0xef12fc03, KEY_MEDIA_REPEAT},
|
{ 0x10ed03, KEY_MEDIA_REPEAT},
|
||||||
{ 0xef12fd02, KEY_PAUSE },
|
{ 0x10ed02, KEY_PAUSE },
|
||||||
{ 0xef12a15e, KEY_VOLUMEUP },
|
{ 0x10ed5e, KEY_VOLUMEUP },
|
||||||
{ 0xef12a35c, KEY_VOLUMEDOWN },
|
{ 0x10ed5c, KEY_VOLUMEDOWN },
|
||||||
{ 0xef12f609, KEY_CHANNELUP },
|
{ 0x10ed09, KEY_CHANNELUP },
|
||||||
{ 0xef12e51a, KEY_CHANNELDOWN },
|
{ 0x10ed1a, KEY_CHANNELDOWN },
|
||||||
{ 0xef12e11e, KEY_PLAY },
|
{ 0x10ed1e, KEY_PLAY },
|
||||||
{ 0xef12e41b, KEY_ZOOM },
|
{ 0x10ed1b, KEY_ZOOM },
|
||||||
{ 0xef12a659, KEY_MUTE },
|
{ 0x10ed59, KEY_MUTE },
|
||||||
{ 0xef12a55a, KEY_TV },
|
{ 0x10ed5a, KEY_TV },
|
||||||
{ 0xef12e718, KEY_RECORD },
|
{ 0x10ed18, KEY_RECORD },
|
||||||
{ 0xef12f807, KEY_EPG },
|
{ 0x10ed07, KEY_EPG },
|
||||||
{ 0xef12fe01, KEY_STOP },
|
{ 0x10ed01, KEY_STOP },
|
||||||
/* Type 2 - 20 buttons */
|
/* Type 2 - 20 buttons */
|
||||||
{ 0xff40ea15, KEY_0 },
|
{ 0xbf15, KEY_0 },
|
||||||
{ 0xff40f708, KEY_1 },
|
{ 0xbf08, KEY_1 },
|
||||||
{ 0xff40f609, KEY_2 },
|
{ 0xbf09, KEY_2 },
|
||||||
{ 0xff40f50a, KEY_3 },
|
{ 0xbf0a, KEY_3 },
|
||||||
{ 0xff40f30c, KEY_4 },
|
{ 0xbf0c, KEY_4 },
|
||||||
{ 0xff40f20d, KEY_5 },
|
{ 0xbf0d, KEY_5 },
|
||||||
{ 0xff40f10e, KEY_6 },
|
{ 0xbf0e, KEY_6 },
|
||||||
{ 0xff40ef10, KEY_7 },
|
{ 0xbf10, KEY_7 },
|
||||||
{ 0xff40ee11, KEY_8 },
|
{ 0xbf11, KEY_8 },
|
||||||
{ 0xff40ed12, KEY_9 },
|
{ 0xbf12, KEY_9 },
|
||||||
{ 0xff40ff00, KEY_POWER },
|
{ 0xbf00, KEY_POWER },
|
||||||
{ 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */
|
{ 0xbf04, KEY_MEDIA_REPEAT}, /* Recall */
|
||||||
{ 0xff40e51a, KEY_PAUSE }, /* Timeshift */
|
{ 0xbf1a, KEY_PAUSE }, /* Timeshift */
|
||||||
{ 0xff40fd02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
|
{ 0xbf02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
|
||||||
{ 0xff40f906, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
|
{ 0xbf06, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
|
||||||
{ 0xff40fe01, KEY_CHANNELUP },
|
{ 0xbf01, KEY_CHANNELUP },
|
||||||
{ 0xff40fa05, KEY_CHANNELDOWN },
|
{ 0xbf05, KEY_CHANNELDOWN },
|
||||||
{ 0xff40eb14, KEY_ZOOM },
|
{ 0xbf14, KEY_ZOOM },
|
||||||
{ 0xff40e718, KEY_RECORD },
|
{ 0xbf18, KEY_RECORD },
|
||||||
{ 0xff40e916, KEY_STOP },
|
{ 0xbf16, KEY_STOP },
|
||||||
/* Type 3 - 20 buttons */
|
/* Type 3 - 20 buttons */
|
||||||
{ 0xff00e31c, KEY_0 },
|
{ 0x1c, KEY_0 },
|
||||||
{ 0xff00f807, KEY_1 },
|
{ 0x07, KEY_1 },
|
||||||
{ 0xff00ea15, KEY_2 },
|
{ 0x15, KEY_2 },
|
||||||
{ 0xff00f609, KEY_3 },
|
{ 0x09, KEY_3 },
|
||||||
{ 0xff00e916, KEY_4 },
|
{ 0x16, KEY_4 },
|
||||||
{ 0xff00e619, KEY_5 },
|
{ 0x19, KEY_5 },
|
||||||
{ 0xff00f20d, KEY_6 },
|
{ 0x0d, KEY_6 },
|
||||||
{ 0xff00f30c, KEY_7 },
|
{ 0x0c, KEY_7 },
|
||||||
{ 0xff00e718, KEY_8 },
|
{ 0x18, KEY_8 },
|
||||||
{ 0xff00a15e, KEY_9 },
|
{ 0x5e, KEY_9 },
|
||||||
{ 0xff00ba45, KEY_POWER },
|
{ 0x45, KEY_POWER },
|
||||||
{ 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */
|
{ 0x44, KEY_MEDIA_REPEAT}, /* Recall */
|
||||||
{ 0xff00b54a, KEY_PAUSE }, /* Timeshift */
|
{ 0x4a, KEY_PAUSE }, /* Timeshift */
|
||||||
{ 0xff00b847, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
|
{ 0x47, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
|
||||||
{ 0xff00bc43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
|
{ 0x43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
|
||||||
{ 0xff00b946, KEY_CHANNELUP },
|
{ 0x46, KEY_CHANNELUP },
|
||||||
{ 0xff00bf40, KEY_CHANNELDOWN },
|
{ 0x40, KEY_CHANNELDOWN },
|
||||||
{ 0xff00f708, KEY_ZOOM },
|
{ 0x08, KEY_ZOOM },
|
||||||
{ 0xff00bd42, KEY_RECORD },
|
{ 0x42, KEY_RECORD },
|
||||||
{ 0xff00a55a, KEY_STOP },
|
{ 0x5a, KEY_STOP },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct rc_map_list lme2510_map = {
|
static struct rc_map_list lme2510_map = {
|
||||||
.map = {
|
.map = {
|
||||||
.scan = lme2510_rc,
|
.scan = lme2510_rc,
|
||||||
.size = ARRAY_SIZE(lme2510_rc),
|
.size = ARRAY_SIZE(lme2510_rc),
|
||||||
.rc_type = RC_TYPE_UNKNOWN,
|
.rc_type = RC_TYPE_NEC,
|
||||||
.name = RC_MAP_LME2510,
|
.name = RC_MAP_LME2510,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -687,7 +687,7 @@ config VIDEO_HEXIUM_GEMINI
|
||||||
|
|
||||||
config VIDEO_TIMBERDALE
|
config VIDEO_TIMBERDALE
|
||||||
tristate "Support for timberdale Video In/LogiWIN"
|
tristate "Support for timberdale Video In/LogiWIN"
|
||||||
depends on VIDEO_V4L2 && I2C
|
depends on VIDEO_V4L2 && I2C && DMADEVICES
|
||||||
select DMA_ENGINE
|
select DMA_ENGINE
|
||||||
select TIMB_DMA
|
select TIMB_DMA
|
||||||
select VIDEO_ADV7180
|
select VIDEO_ADV7180
|
||||||
|
@ -757,6 +757,8 @@ config VIDEO_NOON010PC30
|
||||||
---help---
|
---help---
|
||||||
This driver supports NOON010PC30 CIF camera from Siliconfile
|
This driver supports NOON010PC30 CIF camera from Siliconfile
|
||||||
|
|
||||||
|
source "drivers/media/video/m5mols/Kconfig"
|
||||||
|
|
||||||
config VIDEO_OMAP3
|
config VIDEO_OMAP3
|
||||||
tristate "OMAP 3 Camera support (EXPERIMENTAL)"
|
tristate "OMAP 3 Camera support (EXPERIMENTAL)"
|
||||||
select OMAP_IOMMU
|
select OMAP_IOMMU
|
||||||
|
@ -952,7 +954,7 @@ config VIDEO_SAMSUNG_S5P_FIMC
|
||||||
|
|
||||||
config VIDEO_S5P_MIPI_CSIS
|
config VIDEO_S5P_MIPI_CSIS
|
||||||
tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
|
tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
|
||||||
depends on VIDEO_V4L2 && PM_RUNTIME && VIDEO_V4L2_SUBDEV_API
|
depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API
|
||||||
---help---
|
---help---
|
||||||
This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver.
|
This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver.
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
|
||||||
obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
|
obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
|
||||||
obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
|
obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
|
||||||
obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
|
obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
|
||||||
|
obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/
|
||||||
|
|
||||||
obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o
|
obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o
|
||||||
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
|
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
|
||||||
|
|
|
@ -438,7 +438,7 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
|
||||||
strcat(vc->card, " (676/");
|
strcat(vc->card, " (676/");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
strcat(vc->card, " (???/");
|
strcat(vc->card, " (XXX/");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (cam->params.version.sensor_flags) {
|
switch (cam->params.version.sensor_flags) {
|
||||||
|
@ -458,7 +458,7 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
|
||||||
strcat(vc->card, "500)");
|
strcat(vc->card, "500)");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
strcat(vc->card, "???)");
|
strcat(vc->card, "XXX)");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
|
||||||
MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver");
|
MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef GSPCA_DEBUG
|
||||||
int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK |
|
int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK |
|
||||||
D_USBI | D_USBO | D_V4L2;
|
D_USBI | D_USBO | D_V4L2;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
config VIDEO_M5MOLS
|
||||||
|
tristate "Fujitsu M-5MOLS 8MP sensor support"
|
||||||
|
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
|
||||||
|
---help---
|
||||||
|
This driver supports Fujitsu M-5MOLS camera sensor with ISP
|
|
@ -0,0 +1,3 @@
|
||||||
|
m5mols-objs := m5mols_core.o m5mols_controls.o m5mols_capture.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_VIDEO_M5MOLS) += m5mols.o
|
|
@ -0,0 +1,296 @@
|
||||||
|
/*
|
||||||
|
* Header for M-5MOLS 8M Pixel camera sensor with ISP
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
|
||||||
|
* Author: HeungJun Kim, riverful.kim@samsung.com
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Samsung Electronics Co., Ltd.
|
||||||
|
* Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef M5MOLS_H
|
||||||
|
#define M5MOLS_H
|
||||||
|
|
||||||
|
#include <media/v4l2-subdev.h>
|
||||||
|
#include "m5mols_reg.h"
|
||||||
|
|
||||||
|
extern int m5mols_debug;
|
||||||
|
|
||||||
|
#define to_m5mols(__sd) container_of(__sd, struct m5mols_info, sd)
|
||||||
|
|
||||||
|
#define to_sd(__ctrl) \
|
||||||
|
(&container_of(__ctrl->handler, struct m5mols_info, handle)->sd)
|
||||||
|
|
||||||
|
enum m5mols_restype {
|
||||||
|
M5MOLS_RESTYPE_MONITOR,
|
||||||
|
M5MOLS_RESTYPE_CAPTURE,
|
||||||
|
M5MOLS_RESTYPE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct m5mols_resolution - structure for the resolution
|
||||||
|
* @type: resolution type according to the pixel code
|
||||||
|
* @width: width of the resolution
|
||||||
|
* @height: height of the resolution
|
||||||
|
* @reg: resolution preset register value
|
||||||
|
*/
|
||||||
|
struct m5mols_resolution {
|
||||||
|
u8 reg;
|
||||||
|
enum m5mols_restype type;
|
||||||
|
u16 width;
|
||||||
|
u16 height;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct m5mols_exif - structure for the EXIF information of M-5MOLS
|
||||||
|
* @exposure_time: exposure time register value
|
||||||
|
* @shutter_speed: speed of the shutter register value
|
||||||
|
* @aperture: aperture register value
|
||||||
|
* @exposure_bias: it calls also EV bias
|
||||||
|
* @iso_speed: ISO register value
|
||||||
|
* @flash: status register value of the flash
|
||||||
|
* @sdr: status register value of the Subject Distance Range
|
||||||
|
* @qval: not written exact meaning in document
|
||||||
|
*/
|
||||||
|
struct m5mols_exif {
|
||||||
|
u32 exposure_time;
|
||||||
|
u32 shutter_speed;
|
||||||
|
u32 aperture;
|
||||||
|
u32 brightness;
|
||||||
|
u32 exposure_bias;
|
||||||
|
u16 iso_speed;
|
||||||
|
u16 flash;
|
||||||
|
u16 sdr;
|
||||||
|
u16 qval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct m5mols_capture - Structure for the capture capability
|
||||||
|
* @exif: EXIF information
|
||||||
|
* @main: size in bytes of the main image
|
||||||
|
* @thumb: size in bytes of the thumb image, if it was accompanied
|
||||||
|
* @total: total size in bytes of the produced image
|
||||||
|
*/
|
||||||
|
struct m5mols_capture {
|
||||||
|
struct m5mols_exif exif;
|
||||||
|
u32 main;
|
||||||
|
u32 thumb;
|
||||||
|
u32 total;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct m5mols_scenemode - structure for the scenemode capability
|
||||||
|
* @metering: metering light register value
|
||||||
|
* @ev_bias: EV bias register value
|
||||||
|
* @wb_mode: mode which means the WhiteBalance is Auto or Manual
|
||||||
|
* @wb_preset: whitebalance preset register value in the Manual mode
|
||||||
|
* @chroma_en: register value whether the Chroma capability is enabled or not
|
||||||
|
* @chroma_lvl: chroma's level register value
|
||||||
|
* @edge_en: register value Whether the Edge capability is enabled or not
|
||||||
|
* @edge_lvl: edge's level register value
|
||||||
|
* @af_range: Auto Focus's range
|
||||||
|
* @fd_mode: Face Detection mode
|
||||||
|
* @mcc: Multi-axis Color Conversion which means emotion color
|
||||||
|
* @light: status of the Light
|
||||||
|
* @flash: status of the Flash
|
||||||
|
* @tone: Tone color which means Contrast
|
||||||
|
* @iso: ISO register value
|
||||||
|
* @capt_mode: Mode of the Image Stabilization while the camera capturing
|
||||||
|
* @wdr: Wide Dynamic Range register value
|
||||||
|
*
|
||||||
|
* The each value according to each scenemode is recommended in the documents.
|
||||||
|
*/
|
||||||
|
struct m5mols_scenemode {
|
||||||
|
u32 metering;
|
||||||
|
u32 ev_bias;
|
||||||
|
u32 wb_mode;
|
||||||
|
u32 wb_preset;
|
||||||
|
u32 chroma_en;
|
||||||
|
u32 chroma_lvl;
|
||||||
|
u32 edge_en;
|
||||||
|
u32 edge_lvl;
|
||||||
|
u32 af_range;
|
||||||
|
u32 fd_mode;
|
||||||
|
u32 mcc;
|
||||||
|
u32 light;
|
||||||
|
u32 flash;
|
||||||
|
u32 tone;
|
||||||
|
u32 iso;
|
||||||
|
u32 capt_mode;
|
||||||
|
u32 wdr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct m5mols_version - firmware version information
|
||||||
|
* @customer: customer information
|
||||||
|
* @project: version of project information according to customer
|
||||||
|
* @fw: firmware revision
|
||||||
|
* @hw: hardware revision
|
||||||
|
* @param: version of the parameter
|
||||||
|
* @awb: Auto WhiteBalance algorithm version
|
||||||
|
* @str: information about manufacturer and packaging vendor
|
||||||
|
* @af: Auto Focus version
|
||||||
|
*
|
||||||
|
* The register offset starts the customer version at 0x0, and it ends
|
||||||
|
* the awb version at 0x09. The customer, project information occupies 1 bytes
|
||||||
|
* each. And also the fw, hw, param, awb each requires 2 bytes. The str is
|
||||||
|
* unique string associated with firmware's version. It includes information
|
||||||
|
* about manufacturer and the vendor of the sensor's packaging. The least
|
||||||
|
* significant 2 bytes of the string indicate packaging manufacturer.
|
||||||
|
*/
|
||||||
|
#define VERSION_STRING_SIZE 22
|
||||||
|
struct m5mols_version {
|
||||||
|
u8 customer;
|
||||||
|
u8 project;
|
||||||
|
u16 fw;
|
||||||
|
u16 hw;
|
||||||
|
u16 param;
|
||||||
|
u16 awb;
|
||||||
|
u8 str[VERSION_STRING_SIZE];
|
||||||
|
u8 af;
|
||||||
|
};
|
||||||
|
#define VERSION_SIZE sizeof(struct m5mols_version)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct m5mols_info - M-5MOLS driver data structure
|
||||||
|
* @pdata: platform data
|
||||||
|
* @sd: v4l-subdev instance
|
||||||
|
* @pad: media pad
|
||||||
|
* @ffmt: current fmt according to resolution type
|
||||||
|
* @res_type: current resolution type
|
||||||
|
* @code: current code
|
||||||
|
* @irq_waitq: waitqueue for the capture
|
||||||
|
* @work_irq: workqueue for the IRQ
|
||||||
|
* @flags: state variable for the interrupt handler
|
||||||
|
* @handle: control handler
|
||||||
|
* @autoexposure: Auto Exposure control
|
||||||
|
* @exposure: Exposure control
|
||||||
|
* @autowb: Auto White Balance control
|
||||||
|
* @colorfx: Color effect control
|
||||||
|
* @saturation: Saturation control
|
||||||
|
* @zoom: Zoom control
|
||||||
|
* @ver: information of the version
|
||||||
|
* @cap: the capture mode attributes
|
||||||
|
* @power: current sensor's power status
|
||||||
|
* @ctrl_sync: true means all controls of the sensor are initialized
|
||||||
|
* @int_capture: true means the capture interrupt is issued once
|
||||||
|
* @lock_ae: true means the Auto Exposure is locked
|
||||||
|
* @lock_awb: true means the Aut WhiteBalance is locked
|
||||||
|
* @resolution: register value for current resolution
|
||||||
|
* @interrupt: register value for current interrupt status
|
||||||
|
* @mode: register value for current operation mode
|
||||||
|
* @mode_save: register value for current operation mode for saving
|
||||||
|
* @set_power: optional power callback to the board code
|
||||||
|
*/
|
||||||
|
struct m5mols_info {
|
||||||
|
const struct m5mols_platform_data *pdata;
|
||||||
|
struct v4l2_subdev sd;
|
||||||
|
struct media_pad pad;
|
||||||
|
struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
|
||||||
|
int res_type;
|
||||||
|
enum v4l2_mbus_pixelcode code;
|
||||||
|
wait_queue_head_t irq_waitq;
|
||||||
|
struct work_struct work_irq;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
struct v4l2_ctrl_handler handle;
|
||||||
|
/* Autoexposure/exposure control cluster */
|
||||||
|
struct {
|
||||||
|
struct v4l2_ctrl *autoexposure;
|
||||||
|
struct v4l2_ctrl *exposure;
|
||||||
|
};
|
||||||
|
struct v4l2_ctrl *autowb;
|
||||||
|
struct v4l2_ctrl *colorfx;
|
||||||
|
struct v4l2_ctrl *saturation;
|
||||||
|
struct v4l2_ctrl *zoom;
|
||||||
|
|
||||||
|
struct m5mols_version ver;
|
||||||
|
struct m5mols_capture cap;
|
||||||
|
bool power;
|
||||||
|
bool ctrl_sync;
|
||||||
|
bool lock_ae;
|
||||||
|
bool lock_awb;
|
||||||
|
u8 resolution;
|
||||||
|
u32 interrupt;
|
||||||
|
u32 mode;
|
||||||
|
u32 mode_save;
|
||||||
|
int (*set_power)(struct device *dev, int on);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ST_CAPT_IRQ 0
|
||||||
|
|
||||||
|
#define is_powered(__info) (__info->power)
|
||||||
|
#define is_ctrl_synced(__info) (__info->ctrl_sync)
|
||||||
|
#define is_available_af(__info) (__info->ver.af)
|
||||||
|
#define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code)
|
||||||
|
#define is_manufacturer(__info, __manufacturer) \
|
||||||
|
(__info->ver.str[0] == __manufacturer[0] && \
|
||||||
|
__info->ver.str[1] == __manufacturer[1])
|
||||||
|
/*
|
||||||
|
* I2C operation of the M-5MOLS
|
||||||
|
*
|
||||||
|
* The I2C read operation of the M-5MOLS requires 2 messages. The first
|
||||||
|
* message sends the information about the command, command category, and total
|
||||||
|
* message size. The second message is used to retrieve the data specifed in
|
||||||
|
* the first message
|
||||||
|
*
|
||||||
|
* 1st message 2nd message
|
||||||
|
* +-------+---+----------+-----+-------+ +------+------+------+------+
|
||||||
|
* | size1 | R | category | cmd | size2 | | d[0] | d[1] | d[2] | d[3] |
|
||||||
|
* +-------+---+----------+-----+-------+ +------+------+------+------+
|
||||||
|
* - size1: message data size(5 in this case)
|
||||||
|
* - size2: desired buffer size of the 2nd message
|
||||||
|
* - d[0..3]: according to size2
|
||||||
|
*
|
||||||
|
* The I2C write operation needs just one message. The message includes
|
||||||
|
* category, command, total size, and desired data.
|
||||||
|
*
|
||||||
|
* 1st message
|
||||||
|
* +-------+---+----------+-----+------+------+------+------+
|
||||||
|
* | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] |
|
||||||
|
* +-------+---+----------+-----+------+------+------+------+
|
||||||
|
* - d[0..3]: according to size1
|
||||||
|
*/
|
||||||
|
int m5mols_read(struct v4l2_subdev *sd, u32 reg_comb, u32 *val);
|
||||||
|
int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val);
|
||||||
|
int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mode operation of the M-5MOLS
|
||||||
|
*
|
||||||
|
* Changing the mode of the M-5MOLS is needed right executing order.
|
||||||
|
* There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed
|
||||||
|
* by user. There are various categories associated with each mode.
|
||||||
|
*
|
||||||
|
* +============================================================+
|
||||||
|
* | mode | category |
|
||||||
|
* +============================================================+
|
||||||
|
* | FLASH | FLASH(only after Stand-by or Power-on) |
|
||||||
|
* | SYSTEM | SYSTEM(only after sensor arm-booting) |
|
||||||
|
* | PARAMETER | PARAMETER |
|
||||||
|
* | MONITOR | MONITOR(preview), Auto Focus, Face Detection |
|
||||||
|
* | CAPTURE | Single CAPTURE, Preview(recording) |
|
||||||
|
* +============================================================+
|
||||||
|
*
|
||||||
|
* The available executing order between each modes are as follows:
|
||||||
|
* PARAMETER <---> MONITOR <---> CAPTURE
|
||||||
|
*/
|
||||||
|
int m5mols_mode(struct m5mols_info *info, u32 mode);
|
||||||
|
|
||||||
|
int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg);
|
||||||
|
int m5mols_sync_controls(struct m5mols_info *info);
|
||||||
|
int m5mols_start_capture(struct m5mols_info *info);
|
||||||
|
int m5mols_do_scenemode(struct m5mols_info *info, u32 mode);
|
||||||
|
int m5mols_lock_3a(struct m5mols_info *info, bool lock);
|
||||||
|
int m5mols_set_ctrl(struct v4l2_ctrl *ctrl);
|
||||||
|
|
||||||
|
/* The firmware function */
|
||||||
|
int m5mols_update_fw(struct v4l2_subdev *sd,
|
||||||
|
int (*set_power)(struct m5mols_info *, bool));
|
||||||
|
|
||||||
|
#endif /* M5MOLS_H */
|
|
@ -0,0 +1,191 @@
|
||||||
|
/*
|
||||||
|
* The Capture code for Fujitsu M-5MOLS ISP
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
|
||||||
|
* Author: HeungJun Kim, riverful.kim@samsung.com
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Samsung Electronics Co., Ltd.
|
||||||
|
* Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <media/v4l2-ctrls.h>
|
||||||
|
#include <media/v4l2-device.h>
|
||||||
|
#include <media/v4l2-subdev.h>
|
||||||
|
#include <media/m5mols.h>
|
||||||
|
|
||||||
|
#include "m5mols.h"
|
||||||
|
#include "m5mols_reg.h"
|
||||||
|
|
||||||
|
static int m5mols_capture_error_handler(struct m5mols_info *info,
|
||||||
|
int timeout)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Disable all interrupts and clear relevant interrupt staus bits */
|
||||||
|
ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE,
|
||||||
|
info->interrupt & ~(REG_INT_CAPTURE));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (timeout == 0)
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* m5mols_read_rational - I2C read of a rational number
|
||||||
|
*
|
||||||
|
* Read numerator and denominator from registers @addr_num and @addr_den
|
||||||
|
* respectively and return the division result in @val.
|
||||||
|
*/
|
||||||
|
static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num,
|
||||||
|
u32 addr_den, u32 *val)
|
||||||
|
{
|
||||||
|
u32 num, den;
|
||||||
|
|
||||||
|
int ret = m5mols_read(sd, addr_num, &num);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_read(sd, addr_den, &den);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
*val = den == 0 ? 0 : num / den;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* m5mols_capture_info - Gather captured image information
|
||||||
|
*
|
||||||
|
* For now it gathers only EXIF information and file size.
|
||||||
|
*/
|
||||||
|
static int m5mols_capture_info(struct m5mols_info *info)
|
||||||
|
{
|
||||||
|
struct m5mols_exif *exif = &info->cap.exif;
|
||||||
|
struct v4l2_subdev *sd = &info->sd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = m5mols_read_rational(sd, EXIF_INFO_EXPTIME_NU,
|
||||||
|
EXIF_INFO_EXPTIME_DE, &exif->exposure_time);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = m5mols_read_rational(sd, EXIF_INFO_TV_NU, EXIF_INFO_TV_DE,
|
||||||
|
&exif->shutter_speed);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = m5mols_read_rational(sd, EXIF_INFO_AV_NU, EXIF_INFO_AV_DE,
|
||||||
|
&exif->aperture);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = m5mols_read_rational(sd, EXIF_INFO_BV_NU, EXIF_INFO_BV_DE,
|
||||||
|
&exif->brightness);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = m5mols_read_rational(sd, EXIF_INFO_EBV_NU, EXIF_INFO_EBV_DE,
|
||||||
|
&exif->exposure_bias);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = m5mols_read(sd, EXIF_INFO_ISO, (u32 *)&exif->iso_speed);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_read(sd, EXIF_INFO_FLASH, (u32 *)&exif->flash);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_read(sd, EXIF_INFO_SDR, (u32 *)&exif->sdr);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_read(sd, EXIF_INFO_QVAL, (u32 *)&exif->qval);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_read(sd, CAPC_IMAGE_SIZE, &info->cap.main);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_read(sd, CAPC_THUMB_SIZE, &info->cap.thumb);
|
||||||
|
if (!ret)
|
||||||
|
info->cap.total = info->cap.main + info->cap.thumb;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int m5mols_start_capture(struct m5mols_info *info)
|
||||||
|
{
|
||||||
|
struct v4l2_subdev *sd = &info->sd;
|
||||||
|
u32 resolution = info->resolution;
|
||||||
|
int timeout;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Preparing capture. Setting control & interrupt before entering
|
||||||
|
* capture mode
|
||||||
|
*
|
||||||
|
* 1) change to MONITOR mode for operating control & interrupt
|
||||||
|
* 2) set controls (considering v4l2_control value & lock 3A)
|
||||||
|
* 3) set interrupt
|
||||||
|
* 4) change to CAPTURE mode
|
||||||
|
*/
|
||||||
|
ret = m5mols_mode(info, REG_MONITOR);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_sync_controls(info);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_lock_3a(info, true);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_mode(info, REG_CAPTURE);
|
||||||
|
if (!ret) {
|
||||||
|
/* Wait for capture interrupt, after changing capture mode */
|
||||||
|
timeout = wait_event_interruptible_timeout(info->irq_waitq,
|
||||||
|
test_bit(ST_CAPT_IRQ, &info->flags),
|
||||||
|
msecs_to_jiffies(2000));
|
||||||
|
if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags))
|
||||||
|
ret = m5mols_capture_error_handler(info, timeout);
|
||||||
|
}
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_lock_3a(info, false);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
/*
|
||||||
|
* Starting capture. Setting capture frame count and resolution and
|
||||||
|
* the format(available format: JPEG, Bayer RAW, YUV).
|
||||||
|
*
|
||||||
|
* 1) select single or multi(enable to 25), format, size
|
||||||
|
* 2) set interrupt
|
||||||
|
* 3) start capture(for main image, now)
|
||||||
|
* 4) get information
|
||||||
|
* 5) notify file size to v4l2 device(e.g, to s5p-fimc v4l2 device)
|
||||||
|
*/
|
||||||
|
ret = m5mols_write(sd, CAPC_SEL_FRAME, 1);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN);
|
||||||
|
if (!ret) {
|
||||||
|
/* Wait for the capture completion interrupt */
|
||||||
|
timeout = wait_event_interruptible_timeout(info->irq_waitq,
|
||||||
|
test_bit(ST_CAPT_IRQ, &info->flags),
|
||||||
|
msecs_to_jiffies(2000));
|
||||||
|
if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) {
|
||||||
|
ret = m5mols_capture_info(info);
|
||||||
|
if (!ret)
|
||||||
|
v4l2_subdev_notify(sd, 0, &info->cap.total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m5mols_capture_error_handler(info, timeout);
|
||||||
|
}
|
|
@ -0,0 +1,299 @@
|
||||||
|
/*
|
||||||
|
* Controls for M-5MOLS 8M Pixel camera sensor with ISP
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
|
||||||
|
* Author: HeungJun Kim, riverful.kim@samsung.com
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Samsung Electronics Co., Ltd.
|
||||||
|
* Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
#include <media/v4l2-ctrls.h>
|
||||||
|
|
||||||
|
#include "m5mols.h"
|
||||||
|
#include "m5mols_reg.h"
|
||||||
|
|
||||||
|
static struct m5mols_scenemode m5mols_default_scenemode[] = {
|
||||||
|
[REG_SCENE_NORMAL] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
|
||||||
|
REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
|
||||||
|
REG_AF_NORMAL, REG_FD_OFF,
|
||||||
|
REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
[REG_SCENE_PORTRAIT] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
|
||||||
|
REG_CHROMA_ON, 3, REG_EDGE_ON, 4,
|
||||||
|
REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
[REG_SCENE_LANDSCAPE] = {
|
||||||
|
REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
|
||||||
|
REG_CHROMA_ON, 4, REG_EDGE_ON, 6,
|
||||||
|
REG_AF_NORMAL, REG_FD_OFF,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
[REG_SCENE_SPORTS] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
|
||||||
|
REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
|
||||||
|
REG_AF_NORMAL, REG_FD_OFF,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
[REG_SCENE_PARTY_INDOOR] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
|
||||||
|
REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
|
||||||
|
REG_AF_NORMAL, REG_FD_OFF,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
[REG_SCENE_BEACH_SNOW] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0,
|
||||||
|
REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
|
||||||
|
REG_AF_NORMAL, REG_FD_OFF,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
[REG_SCENE_SUNSET] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
|
||||||
|
REG_AWB_DAYLIGHT,
|
||||||
|
REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
|
||||||
|
REG_AF_NORMAL, REG_FD_OFF,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
[REG_SCENE_DAWN_DUSK] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
|
||||||
|
REG_AWB_FLUORESCENT_1,
|
||||||
|
REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
|
||||||
|
REG_AF_NORMAL, REG_FD_OFF,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
[REG_SCENE_FALL] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
|
||||||
|
REG_CHROMA_ON, 5, REG_EDGE_ON, 5,
|
||||||
|
REG_AF_NORMAL, REG_FD_OFF,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
[REG_SCENE_NIGHT] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
|
||||||
|
REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
|
||||||
|
REG_AF_NORMAL, REG_FD_OFF,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
[REG_SCENE_AGAINST_LIGHT] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
|
||||||
|
REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
|
||||||
|
REG_AF_NORMAL, REG_FD_OFF,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
[REG_SCENE_FIRE] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
|
||||||
|
REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
|
||||||
|
REG_AF_NORMAL, REG_FD_OFF,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
[REG_SCENE_TEXT] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
|
||||||
|
REG_CHROMA_ON, 3, REG_EDGE_ON, 7,
|
||||||
|
REG_AF_MACRO, REG_FD_OFF,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON,
|
||||||
|
},
|
||||||
|
[REG_SCENE_CANDLE] = {
|
||||||
|
REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
|
||||||
|
REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
|
||||||
|
REG_AF_NORMAL, REG_FD_OFF,
|
||||||
|
REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
|
||||||
|
6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* m5mols_do_scenemode() - Change current scenemode
|
||||||
|
* @mode: Desired mode of the scenemode
|
||||||
|
*
|
||||||
|
* WARNING: The execution order is important. Do not change the order.
|
||||||
|
*/
|
||||||
|
int m5mols_do_scenemode(struct m5mols_info *info, u32 mode)
|
||||||
|
{
|
||||||
|
struct v4l2_subdev *sd = &info->sd;
|
||||||
|
struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (mode > REG_SCENE_CANDLE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = m5mols_lock_3a(info, false);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, AE_MODE, scenemode.metering);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl);
|
||||||
|
if (!ret && is_available_af(info))
|
||||||
|
ret = m5mols_write(sd, AF_MODE, scenemode.af_range);
|
||||||
|
if (!ret && is_available_af(info))
|
||||||
|
ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, AE_ISO, scenemode.iso);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_mode(info, REG_CAPTURE);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_mode(info, REG_MONITOR);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int m5mols_lock_ae(struct m5mols_info *info, bool lock)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (info->lock_ae != lock)
|
||||||
|
ret = m5mols_write(&info->sd, AE_LOCK,
|
||||||
|
lock ? REG_AE_LOCK : REG_AE_UNLOCK);
|
||||||
|
if (!ret)
|
||||||
|
info->lock_ae = lock;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int m5mols_lock_awb(struct m5mols_info *info, bool lock)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (info->lock_awb != lock)
|
||||||
|
ret = m5mols_write(&info->sd, AWB_LOCK,
|
||||||
|
lock ? REG_AWB_LOCK : REG_AWB_UNLOCK);
|
||||||
|
if (!ret)
|
||||||
|
info->lock_awb = lock;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */
|
||||||
|
int m5mols_lock_3a(struct m5mols_info *info, bool lock)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = m5mols_lock_ae(info, lock);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_lock_awb(info, lock);
|
||||||
|
/* Don't need to handle unlocking AF */
|
||||||
|
if (!ret && is_available_af(info) && lock)
|
||||||
|
ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */
|
||||||
|
int m5mols_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
|
{
|
||||||
|
struct v4l2_subdev *sd = to_sd(ctrl);
|
||||||
|
struct m5mols_info *info = to_m5mols(sd);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (ctrl->id) {
|
||||||
|
case V4L2_CID_ZOOM_ABSOLUTE:
|
||||||
|
return m5mols_write(sd, MON_ZOOM, ctrl->val);
|
||||||
|
|
||||||
|
case V4L2_CID_EXPOSURE_AUTO:
|
||||||
|
ret = m5mols_lock_ae(info,
|
||||||
|
ctrl->val == V4L2_EXPOSURE_AUTO ? false : true);
|
||||||
|
if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO)
|
||||||
|
ret = m5mols_write(sd, AE_MODE, REG_AE_ALL);
|
||||||
|
if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) {
|
||||||
|
int val = info->exposure->val;
|
||||||
|
ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, AE_MAN_GAIN_MON, val);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
case V4L2_CID_AUTO_WHITE_BALANCE:
|
||||||
|
ret = m5mols_lock_awb(info, ctrl->val ? false : true);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, AWB_MODE, ctrl->val ?
|
||||||
|
REG_AWB_AUTO : REG_AWB_PRESET);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
case V4L2_CID_SATURATION:
|
||||||
|
ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
case V4L2_CID_COLORFX:
|
||||||
|
/*
|
||||||
|
* This control uses two kinds of registers: normal & color.
|
||||||
|
* The normal effect belongs to category 1, while the color
|
||||||
|
* one belongs to category 2.
|
||||||
|
*
|
||||||
|
* The normal effect uses one register: CAT1_EFFECT.
|
||||||
|
* The color effect uses three registers:
|
||||||
|
* CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB.
|
||||||
|
*/
|
||||||
|
ret = m5mols_write(sd, PARM_EFFECT,
|
||||||
|
ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA :
|
||||||
|
ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS :
|
||||||
|
REG_EFFECT_OFF);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, MON_EFFECT,
|
||||||
|
ctrl->val == V4L2_COLORFX_SEPIA ?
|
||||||
|
REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, MON_CFIXR,
|
||||||
|
ctrl->val == V4L2_COLORFX_SEPIA ?
|
||||||
|
REG_CFIXR_SEPIA : 0);
|
||||||
|
if (!ret)
|
||||||
|
ret = m5mols_write(sd, MON_CFIXB,
|
||||||
|
ctrl->val == V4L2_COLORFX_SEPIA ?
|
||||||
|
REG_CFIXB_SEPIA : 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,399 @@
|
||||||
|
/*
|
||||||
|
* Register map for M-5MOLS 8M Pixel camera sensor with ISP
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
|
||||||
|
* Author: HeungJun Kim, riverful.kim@samsung.com
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Samsung Electronics Co., Ltd.
|
||||||
|
* Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef M5MOLS_REG_H
|
||||||
|
#define M5MOLS_REG_H
|
||||||
|
|
||||||
|
#define M5MOLS_I2C_MAX_SIZE 4
|
||||||
|
#define M5MOLS_BYTE_READ 0x01
|
||||||
|
#define M5MOLS_BYTE_WRITE 0x02
|
||||||
|
|
||||||
|
#define I2C_CATEGORY(__cat) ((__cat >> 16) & 0xff)
|
||||||
|
#define I2C_COMMAND(__comm) ((__comm >> 8) & 0xff)
|
||||||
|
#define I2C_SIZE(__reg_s) ((__reg_s) & 0xff)
|
||||||
|
#define I2C_REG(__cat, __cmd, __reg_s) ((__cat << 16) | (__cmd << 8) | __reg_s)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Category section register
|
||||||
|
*
|
||||||
|
* The category means set including relevant command of M-5MOLS.
|
||||||
|
*/
|
||||||
|
#define CAT_SYSTEM 0x00
|
||||||
|
#define CAT_PARAM 0x01
|
||||||
|
#define CAT_MONITOR 0x02
|
||||||
|
#define CAT_AE 0x03
|
||||||
|
#define CAT_WB 0x06
|
||||||
|
#define CAT_EXIF 0x07
|
||||||
|
#define CAT_FD 0x09
|
||||||
|
#define CAT_LENS 0x0a
|
||||||
|
#define CAT_CAPT_PARM 0x0b
|
||||||
|
#define CAT_CAPT_CTRL 0x0c
|
||||||
|
#define CAT_FLASH 0x0f /* related to FW, revisions, booting */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Category 0 - SYSTEM mode
|
||||||
|
*
|
||||||
|
* The SYSTEM mode in the M-5MOLS means area available to handle with the whole
|
||||||
|
* & all-round system of sensor. It deals with version/interrupt/setting mode &
|
||||||
|
* even sensor's status. Especially, the M-5MOLS sensor with ISP varies by
|
||||||
|
* packaging & manufacturer, even the customer and project code. And the
|
||||||
|
* function details may vary among them. The version information helps to
|
||||||
|
* determine what methods shall be used in the driver.
|
||||||
|
*
|
||||||
|
* There is many registers between customer version address and awb one. For
|
||||||
|
* more specific contents, see definition if file m5mols.h.
|
||||||
|
*/
|
||||||
|
#define CAT0_VER_CUSTOMER 0x00 /* customer version */
|
||||||
|
#define CAT0_VER_AWB 0x09 /* Auto WB version */
|
||||||
|
#define CAT0_VER_STRING 0x0a /* string including M-5MOLS */
|
||||||
|
#define CAT0_SYSMODE 0x0b /* SYSTEM mode register */
|
||||||
|
#define CAT0_STATUS 0x0c /* SYSTEM mode status register */
|
||||||
|
#define CAT0_INT_FACTOR 0x10 /* interrupt pending register */
|
||||||
|
#define CAT0_INT_ENABLE 0x11 /* interrupt enable register */
|
||||||
|
|
||||||
|
#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1)
|
||||||
|
#define REG_SYSINIT 0x00 /* SYSTEM mode */
|
||||||
|
#define REG_PARAMETER 0x01 /* PARAMETER mode */
|
||||||
|
#define REG_MONITOR 0x02 /* MONITOR mode */
|
||||||
|
#define REG_CAPTURE 0x03 /* CAPTURE mode */
|
||||||
|
|
||||||
|
#define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1)
|
||||||
|
#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1)
|
||||||
|
#define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */
|
||||||
|
#define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */
|
||||||
|
#define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */
|
||||||
|
|
||||||
|
#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1)
|
||||||
|
#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1)
|
||||||
|
#define REG_INT_MODE (1 << 0)
|
||||||
|
#define REG_INT_AF (1 << 1)
|
||||||
|
#define REG_INT_ZOOM (1 << 2)
|
||||||
|
#define REG_INT_CAPTURE (1 << 3)
|
||||||
|
#define REG_INT_FRAMESYNC (1 << 4)
|
||||||
|
#define REG_INT_FD (1 << 5)
|
||||||
|
#define REG_INT_LENS_INIT (1 << 6)
|
||||||
|
#define REG_INT_SOUND (1 << 7)
|
||||||
|
#define REG_INT_MASK 0x0f
|
||||||
|
|
||||||
|
/*
|
||||||
|
* category 1 - PARAMETER mode
|
||||||
|
*
|
||||||
|
* This category supports function of camera features of M-5MOLS. It means we
|
||||||
|
* can handle with preview(MONITOR) resolution size/frame per second/interface
|
||||||
|
* between the sensor and the Application Processor/even the image effect.
|
||||||
|
*/
|
||||||
|
#define CAT1_DATA_INTERFACE 0x00 /* interface between sensor and AP */
|
||||||
|
#define CAT1_MONITOR_SIZE 0x01 /* resolution at the MONITOR mode */
|
||||||
|
#define CAT1_MONITOR_FPS 0x02 /* frame per second at this mode */
|
||||||
|
#define CAT1_EFFECT 0x0b /* image effects */
|
||||||
|
|
||||||
|
#define PARM_MON_SIZE I2C_REG(CAT_PARAM, CAT1_MONITOR_SIZE, 1)
|
||||||
|
|
||||||
|
#define PARM_MON_FPS I2C_REG(CAT_PARAM, CAT1_MONITOR_FPS, 1)
|
||||||
|
#define REG_FPS_30 0x02
|
||||||
|
|
||||||
|
#define PARM_INTERFACE I2C_REG(CAT_PARAM, CAT1_DATA_INTERFACE, 1)
|
||||||
|
#define REG_INTERFACE_MIPI 0x02
|
||||||
|
|
||||||
|
#define PARM_EFFECT I2C_REG(CAT_PARAM, CAT1_EFFECT, 1)
|
||||||
|
#define REG_EFFECT_OFF 0x00
|
||||||
|
#define REG_EFFECT_NEGA 0x01
|
||||||
|
#define REG_EFFECT_EMBOSS 0x06
|
||||||
|
#define REG_EFFECT_OUTLINE 0x07
|
||||||
|
#define REG_EFFECT_WATERCOLOR 0x08
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Category 2 - MONITOR mode
|
||||||
|
*
|
||||||
|
* The MONITOR mode is same as preview mode as we said. The M-5MOLS has another
|
||||||
|
* mode named "Preview", but this preview mode is used at the case specific
|
||||||
|
* vider-recording mode. This mmode supports only YUYV format. On the other
|
||||||
|
* hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are
|
||||||
|
* another options like zoom/color effect(different with effect in PARAMETER
|
||||||
|
* mode)/anti hand shaking algorithm.
|
||||||
|
*/
|
||||||
|
#define CAT2_ZOOM 0x01 /* set the zoom position & execute */
|
||||||
|
#define CAT2_ZOOM_STEP 0x03 /* set the zoom step */
|
||||||
|
#define CAT2_CFIXB 0x09 /* CB value for color effect */
|
||||||
|
#define CAT2_CFIXR 0x0a /* CR value for color effect */
|
||||||
|
#define CAT2_COLOR_EFFECT 0x0b /* set on/off of color effect */
|
||||||
|
#define CAT2_CHROMA_LVL 0x0f /* set chroma level */
|
||||||
|
#define CAT2_CHROMA_EN 0x10 /* set on/off of choroma */
|
||||||
|
#define CAT2_EDGE_LVL 0x11 /* set sharpness level */
|
||||||
|
#define CAT2_EDGE_EN 0x12 /* set on/off sharpness */
|
||||||
|
#define CAT2_TONE_CTL 0x25 /* set tone color(contrast) */
|
||||||
|
|
||||||
|
#define MON_ZOOM I2C_REG(CAT_MONITOR, CAT2_ZOOM, 1)
|
||||||
|
|
||||||
|
#define MON_CFIXR I2C_REG(CAT_MONITOR, CAT2_CFIXR, 1)
|
||||||
|
#define MON_CFIXB I2C_REG(CAT_MONITOR, CAT2_CFIXB, 1)
|
||||||
|
#define REG_CFIXB_SEPIA 0xd8
|
||||||
|
#define REG_CFIXR_SEPIA 0x18
|
||||||
|
|
||||||
|
#define MON_EFFECT I2C_REG(CAT_MONITOR, CAT2_COLOR_EFFECT, 1)
|
||||||
|
#define REG_COLOR_EFFECT_OFF 0x00
|
||||||
|
#define REG_COLOR_EFFECT_ON 0x01
|
||||||
|
|
||||||
|
#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, CAT2_CHROMA_EN, 1)
|
||||||
|
#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, CAT2_CHROMA_LVL, 1)
|
||||||
|
#define REG_CHROMA_OFF 0x00
|
||||||
|
#define REG_CHROMA_ON 0x01
|
||||||
|
|
||||||
|
#define MON_EDGE_EN I2C_REG(CAT_MONITOR, CAT2_EDGE_EN, 1)
|
||||||
|
#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, CAT2_EDGE_LVL, 1)
|
||||||
|
#define REG_EDGE_OFF 0x00
|
||||||
|
#define REG_EDGE_ON 0x01
|
||||||
|
|
||||||
|
#define MON_TONE_CTL I2C_REG(CAT_MONITOR, CAT2_TONE_CTL, 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Category 3 - Auto Exposure
|
||||||
|
*
|
||||||
|
* The M-5MOLS exposure capbility is detailed as which is similar to digital
|
||||||
|
* camera. This category supports AE locking/various AE mode(range of exposure)
|
||||||
|
* /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the
|
||||||
|
* maximum/minimum exposure gain value depending on M-5MOLS firmware, may be
|
||||||
|
* different. So, this category also provide getting the max/min values. And,
|
||||||
|
* each MONITOR and CAPTURE mode has each gain/shutter/max exposure values.
|
||||||
|
*/
|
||||||
|
#define CAT3_AE_LOCK 0x00 /* locking Auto exposure */
|
||||||
|
#define CAT3_AE_MODE 0x01 /* set AE mode, mode means range */
|
||||||
|
#define CAT3_ISO 0x05 /* set ISO */
|
||||||
|
#define CAT3_EV_PRESET_MONITOR 0x0a /* EV(scenemode) preset for MONITOR */
|
||||||
|
#define CAT3_EV_PRESET_CAPTURE 0x0b /* EV(scenemode) preset for CAPTURE */
|
||||||
|
#define CAT3_MANUAL_GAIN_MON 0x12 /* meteoring value for the MONITOR */
|
||||||
|
#define CAT3_MAX_GAIN_MON 0x1a /* max gain value for the MONITOR */
|
||||||
|
#define CAT3_MANUAL_GAIN_CAP 0x26 /* meteoring value for the CAPTURE */
|
||||||
|
#define CAT3_AE_INDEX 0x38 /* AE index */
|
||||||
|
|
||||||
|
#define AE_LOCK I2C_REG(CAT_AE, CAT3_AE_LOCK, 1)
|
||||||
|
#define REG_AE_UNLOCK 0x00
|
||||||
|
#define REG_AE_LOCK 0x01
|
||||||
|
|
||||||
|
#define AE_MODE I2C_REG(CAT_AE, CAT3_AE_MODE, 1)
|
||||||
|
#define REG_AE_OFF 0x00 /* AE off */
|
||||||
|
#define REG_AE_ALL 0x01 /* calc AE in all block integral */
|
||||||
|
#define REG_AE_CENTER 0x03 /* calc AE in center weighted */
|
||||||
|
#define REG_AE_SPOT 0x06 /* calc AE in specific spot */
|
||||||
|
|
||||||
|
#define AE_ISO I2C_REG(CAT_AE, CAT3_ISO, 1)
|
||||||
|
#define REG_ISO_AUTO 0x00
|
||||||
|
#define REG_ISO_50 0x01
|
||||||
|
#define REG_ISO_100 0x02
|
||||||
|
#define REG_ISO_200 0x03
|
||||||
|
#define REG_ISO_400 0x04
|
||||||
|
#define REG_ISO_800 0x05
|
||||||
|
|
||||||
|
#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, CAT3_EV_PRESET_MONITOR, 1)
|
||||||
|
#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, CAT3_EV_PRESET_CAPTURE, 1)
|
||||||
|
#define REG_SCENE_NORMAL 0x00
|
||||||
|
#define REG_SCENE_PORTRAIT 0x01
|
||||||
|
#define REG_SCENE_LANDSCAPE 0x02
|
||||||
|
#define REG_SCENE_SPORTS 0x03
|
||||||
|
#define REG_SCENE_PARTY_INDOOR 0x04
|
||||||
|
#define REG_SCENE_BEACH_SNOW 0x05
|
||||||
|
#define REG_SCENE_SUNSET 0x06
|
||||||
|
#define REG_SCENE_DAWN_DUSK 0x07
|
||||||
|
#define REG_SCENE_FALL 0x08
|
||||||
|
#define REG_SCENE_NIGHT 0x09
|
||||||
|
#define REG_SCENE_AGAINST_LIGHT 0x0a
|
||||||
|
#define REG_SCENE_FIRE 0x0b
|
||||||
|
#define REG_SCENE_TEXT 0x0c
|
||||||
|
#define REG_SCENE_CANDLE 0x0d
|
||||||
|
|
||||||
|
#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_MON, 2)
|
||||||
|
#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, CAT3_MAX_GAIN_MON, 2)
|
||||||
|
#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_CAP, 2)
|
||||||
|
|
||||||
|
#define AE_INDEX I2C_REG(CAT_AE, CAT3_AE_INDEX, 1)
|
||||||
|
#define REG_AE_INDEX_20_NEG 0x00
|
||||||
|
#define REG_AE_INDEX_15_NEG 0x01
|
||||||
|
#define REG_AE_INDEX_10_NEG 0x02
|
||||||
|
#define REG_AE_INDEX_05_NEG 0x03
|
||||||
|
#define REG_AE_INDEX_00 0x04
|
||||||
|
#define REG_AE_INDEX_05_POS 0x05
|
||||||
|
#define REG_AE_INDEX_10_POS 0x06
|
||||||
|
#define REG_AE_INDEX_15_POS 0x07
|
||||||
|
#define REG_AE_INDEX_20_POS 0x08
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Category 6 - White Balance
|
||||||
|
*
|
||||||
|
* This category provide AWB locking/mode/preset/speed/gain bias, etc.
|
||||||
|
*/
|
||||||
|
#define CAT6_AWB_LOCK 0x00 /* locking Auto Whitebalance */
|
||||||
|
#define CAT6_AWB_MODE 0x02 /* set Auto or Manual */
|
||||||
|
#define CAT6_AWB_MANUAL 0x03 /* set Manual(preset) value */
|
||||||
|
|
||||||
|
#define AWB_LOCK I2C_REG(CAT_WB, CAT6_AWB_LOCK, 1)
|
||||||
|
#define REG_AWB_UNLOCK 0x00
|
||||||
|
#define REG_AWB_LOCK 0x01
|
||||||
|
|
||||||
|
#define AWB_MODE I2C_REG(CAT_WB, CAT6_AWB_MODE, 1)
|
||||||
|
#define REG_AWB_AUTO 0x01 /* AWB off */
|
||||||
|
#define REG_AWB_PRESET 0x02 /* AWB preset */
|
||||||
|
|
||||||
|
#define AWB_MANUAL I2C_REG(CAT_WB, CAT6_AWB_MANUAL, 1)
|
||||||
|
#define REG_AWB_INCANDESCENT 0x01
|
||||||
|
#define REG_AWB_FLUORESCENT_1 0x02
|
||||||
|
#define REG_AWB_FLUORESCENT_2 0x03
|
||||||
|
#define REG_AWB_DAYLIGHT 0x04
|
||||||
|
#define REG_AWB_CLOUDY 0x05
|
||||||
|
#define REG_AWB_SHADE 0x06
|
||||||
|
#define REG_AWB_HORIZON 0x07
|
||||||
|
#define REG_AWB_LEDLIGHT 0x09
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Category 7 - EXIF information
|
||||||
|
*/
|
||||||
|
#define CAT7_INFO_EXPTIME_NU 0x00
|
||||||
|
#define CAT7_INFO_EXPTIME_DE 0x04
|
||||||
|
#define CAT7_INFO_TV_NU 0x08
|
||||||
|
#define CAT7_INFO_TV_DE 0x0c
|
||||||
|
#define CAT7_INFO_AV_NU 0x10
|
||||||
|
#define CAT7_INFO_AV_DE 0x14
|
||||||
|
#define CAT7_INFO_BV_NU 0x18
|
||||||
|
#define CAT7_INFO_BV_DE 0x1c
|
||||||
|
#define CAT7_INFO_EBV_NU 0x20
|
||||||
|
#define CAT7_INFO_EBV_DE 0x24
|
||||||
|
#define CAT7_INFO_ISO 0x28
|
||||||
|
#define CAT7_INFO_FLASH 0x2a
|
||||||
|
#define CAT7_INFO_SDR 0x2c
|
||||||
|
#define CAT7_INFO_QVAL 0x2e
|
||||||
|
|
||||||
|
#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_NU, 4)
|
||||||
|
#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_DE, 4)
|
||||||
|
#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, CAT7_INFO_TV_NU, 4)
|
||||||
|
#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, CAT7_INFO_TV_DE, 4)
|
||||||
|
#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, CAT7_INFO_AV_NU, 4)
|
||||||
|
#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, CAT7_INFO_AV_DE, 4)
|
||||||
|
#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, CAT7_INFO_BV_NU, 4)
|
||||||
|
#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, CAT7_INFO_BV_DE, 4)
|
||||||
|
#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, CAT7_INFO_EBV_NU, 4)
|
||||||
|
#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, CAT7_INFO_EBV_DE, 4)
|
||||||
|
#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, CAT7_INFO_ISO, 2)
|
||||||
|
#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, CAT7_INFO_FLASH, 2)
|
||||||
|
#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, CAT7_INFO_SDR, 2)
|
||||||
|
#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, CAT7_INFO_QVAL, 2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Category 9 - Face Detection
|
||||||
|
*/
|
||||||
|
#define CAT9_FD_CTL 0x00
|
||||||
|
|
||||||
|
#define FD_CTL I2C_REG(CAT_FD, CAT9_FD_CTL, 1)
|
||||||
|
#define BIT_FD_EN 0
|
||||||
|
#define BIT_FD_DRAW_FACE_FRAME 4
|
||||||
|
#define BIT_FD_DRAW_SMILE_LVL 6
|
||||||
|
#define REG_FD(shift) (1 << shift)
|
||||||
|
#define REG_FD_OFF 0x0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Category A - Lens Parameter
|
||||||
|
*/
|
||||||
|
#define CATA_AF_MODE 0x01
|
||||||
|
#define CATA_AF_EXECUTE 0x02
|
||||||
|
#define CATA_AF_STATUS 0x03
|
||||||
|
#define CATA_AF_VERSION 0x0a
|
||||||
|
|
||||||
|
#define AF_MODE I2C_REG(CAT_LENS, CATA_AF_MODE, 1)
|
||||||
|
#define REG_AF_NORMAL 0x00 /* Normal AF, one time */
|
||||||
|
#define REG_AF_MACRO 0x01 /* Macro AF, one time */
|
||||||
|
#define REG_AF_POWEROFF 0x07
|
||||||
|
|
||||||
|
#define AF_EXECUTE I2C_REG(CAT_LENS, CATA_AF_EXECUTE, 1)
|
||||||
|
#define REG_AF_STOP 0x00
|
||||||
|
#define REG_AF_EXE_AUTO 0x01
|
||||||
|
#define REG_AF_EXE_CAF 0x02
|
||||||
|
|
||||||
|
#define AF_STATUS I2C_REG(CAT_LENS, CATA_AF_STATUS, 1)
|
||||||
|
#define REG_AF_FAIL 0x00
|
||||||
|
#define REG_AF_SUCCESS 0x02
|
||||||
|
#define REG_AF_IDLE 0x04
|
||||||
|
#define REG_AF_BUSY 0x05
|
||||||
|
|
||||||
|
#define AF_VERSION I2C_REG(CAT_LENS, CATA_AF_VERSION, 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Category B - CAPTURE Parameter
|
||||||
|
*/
|
||||||
|
#define CATB_YUVOUT_MAIN 0x00
|
||||||
|
#define CATB_MAIN_IMAGE_SIZE 0x01
|
||||||
|
#define CATB_MCC_MODE 0x1d
|
||||||
|
#define CATB_WDR_EN 0x2c
|
||||||
|
#define CATB_LIGHT_CTRL 0x40
|
||||||
|
#define CATB_FLASH_CTRL 0x41
|
||||||
|
|
||||||
|
#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, CATB_YUVOUT_MAIN, 1)
|
||||||
|
#define REG_YUV422 0x00
|
||||||
|
#define REG_BAYER10 0x05
|
||||||
|
#define REG_BAYER8 0x06
|
||||||
|
#define REG_JPEG 0x10
|
||||||
|
|
||||||
|
#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, CATB_MAIN_IMAGE_SIZE, 1)
|
||||||
|
|
||||||
|
#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, CATB_MCC_MODE, 1)
|
||||||
|
#define REG_MCC_OFF 0x00
|
||||||
|
#define REG_MCC_NORMAL 0x01
|
||||||
|
|
||||||
|
#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, CATB_WDR_EN, 1)
|
||||||
|
#define REG_WDR_OFF 0x00
|
||||||
|
#define REG_WDR_ON 0x01
|
||||||
|
#define REG_WDR_AUTO 0x02
|
||||||
|
|
||||||
|
#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, CATB_LIGHT_CTRL, 1)
|
||||||
|
#define REG_LIGHT_OFF 0x00
|
||||||
|
#define REG_LIGHT_ON 0x01
|
||||||
|
#define REG_LIGHT_AUTO 0x02
|
||||||
|
|
||||||
|
#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, CATB_FLASH_CTRL, 1)
|
||||||
|
#define REG_FLASH_OFF 0x00
|
||||||
|
#define REG_FLASH_ON 0x01
|
||||||
|
#define REG_FLASH_AUTO 0x02
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Category C - CAPTURE Control
|
||||||
|
*/
|
||||||
|
#define CATC_CAP_MODE 0x00
|
||||||
|
#define CATC_CAP_SEL_FRAME 0x06 /* It determines Single or Multi */
|
||||||
|
#define CATC_CAP_START 0x09
|
||||||
|
#define CATC_CAP_IMAGE_SIZE 0x0d
|
||||||
|
#define CATC_CAP_THUMB_SIZE 0x11
|
||||||
|
|
||||||
|
#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_MODE, 1)
|
||||||
|
#define REG_CAP_NONE 0x00
|
||||||
|
#define REG_CAP_ANTI_SHAKE 0x02
|
||||||
|
|
||||||
|
#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, CATC_CAP_SEL_FRAME, 1)
|
||||||
|
|
||||||
|
#define CAPC_START I2C_REG(CAT_CAPT_CTRL, CATC_CAP_START, 1)
|
||||||
|
#define REG_CAP_START_MAIN 0x01
|
||||||
|
#define REG_CAP_START_THUMB 0x03
|
||||||
|
|
||||||
|
#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 1)
|
||||||
|
#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Category F - Flash
|
||||||
|
*
|
||||||
|
* This mode provides functions about internal flash stuff and system startup.
|
||||||
|
*/
|
||||||
|
#define CATF_CAM_START 0x12 /* It starts internal ARM core booting
|
||||||
|
* after power-up */
|
||||||
|
|
||||||
|
#define FLASH_CAM_START I2C_REG(CAT_FLASH, CATF_CAM_START, 1)
|
||||||
|
#define REG_START_ARM_BOOT 0x01
|
||||||
|
|
||||||
|
#endif /* M5MOLS_REG_H */
|
|
@ -1,3 +1,6 @@
|
||||||
uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
|
uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
|
||||||
uvc_status.o uvc_isight.o
|
uvc_status.o uvc_isight.o
|
||||||
|
ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
|
||||||
|
uvcvideo-objs += uvc_entity.o
|
||||||
|
endif
|
||||||
obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o
|
obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o
|
||||||
|
|
|
@ -248,7 +248,7 @@ uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
|
||||||
* Terminal and unit management
|
* Terminal and unit management
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
|
struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
|
||||||
{
|
{
|
||||||
struct uvc_entity *entity;
|
struct uvc_entity *entity;
|
||||||
|
|
||||||
|
@ -795,9 +795,12 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
|
||||||
struct uvc_entity *entity;
|
struct uvc_entity *entity;
|
||||||
unsigned int num_inputs;
|
unsigned int num_inputs;
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
extra_size = ALIGN(extra_size, sizeof(*entity->pads));
|
||||||
num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
|
num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
|
||||||
size = sizeof(*entity) + extra_size + num_inputs;
|
size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads
|
||||||
|
+ num_inputs;
|
||||||
entity = kzalloc(size, GFP_KERNEL);
|
entity = kzalloc(size, GFP_KERNEL);
|
||||||
if (entity == NULL)
|
if (entity == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -805,8 +808,17 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
|
||||||
entity->id = id;
|
entity->id = id;
|
||||||
entity->type = type;
|
entity->type = type;
|
||||||
|
|
||||||
|
entity->num_links = 0;
|
||||||
|
entity->num_pads = num_pads;
|
||||||
|
entity->pads = ((void *)(entity + 1)) + extra_size;
|
||||||
|
|
||||||
|
for (i = 0; i < num_inputs; ++i)
|
||||||
|
entity->pads[i].flags = MEDIA_PAD_FL_SINK;
|
||||||
|
if (!UVC_ENTITY_IS_OTERM(entity))
|
||||||
|
entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE;
|
||||||
|
|
||||||
entity->bNrInPins = num_inputs;
|
entity->bNrInPins = num_inputs;
|
||||||
entity->baSourceID = ((__u8 *)entity) + sizeof(*entity) + extra_size;
|
entity->baSourceID = (__u8 *)(&entity->pads[num_pads]);
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
@ -1585,6 +1597,13 @@ static void uvc_delete(struct uvc_device *dev)
|
||||||
uvc_status_cleanup(dev);
|
uvc_status_cleanup(dev);
|
||||||
uvc_ctrl_cleanup_device(dev);
|
uvc_ctrl_cleanup_device(dev);
|
||||||
|
|
||||||
|
if (dev->vdev.dev)
|
||||||
|
v4l2_device_unregister(&dev->vdev);
|
||||||
|
#ifdef CONFIG_MEDIA_CONTROLLER
|
||||||
|
if (media_devnode_is_registered(&dev->mdev.devnode))
|
||||||
|
media_device_unregister(&dev->mdev);
|
||||||
|
#endif
|
||||||
|
|
||||||
list_for_each_safe(p, n, &dev->chains) {
|
list_for_each_safe(p, n, &dev->chains) {
|
||||||
struct uvc_video_chain *chain;
|
struct uvc_video_chain *chain;
|
||||||
chain = list_entry(p, struct uvc_video_chain, list);
|
chain = list_entry(p, struct uvc_video_chain, list);
|
||||||
|
@ -1594,6 +1613,13 @@ static void uvc_delete(struct uvc_device *dev)
|
||||||
list_for_each_safe(p, n, &dev->entities) {
|
list_for_each_safe(p, n, &dev->entities) {
|
||||||
struct uvc_entity *entity;
|
struct uvc_entity *entity;
|
||||||
entity = list_entry(p, struct uvc_entity, list);
|
entity = list_entry(p, struct uvc_entity, list);
|
||||||
|
#ifdef CONFIG_MEDIA_CONTROLLER
|
||||||
|
uvc_mc_cleanup_entity(entity);
|
||||||
|
#endif
|
||||||
|
if (entity->vdev) {
|
||||||
|
video_device_release(entity->vdev);
|
||||||
|
entity->vdev = NULL;
|
||||||
|
}
|
||||||
kfree(entity);
|
kfree(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1616,8 +1642,6 @@ static void uvc_release(struct video_device *vdev)
|
||||||
struct uvc_streaming *stream = video_get_drvdata(vdev);
|
struct uvc_streaming *stream = video_get_drvdata(vdev);
|
||||||
struct uvc_device *dev = stream->dev;
|
struct uvc_device *dev = stream->dev;
|
||||||
|
|
||||||
video_device_release(vdev);
|
|
||||||
|
|
||||||
/* Decrement the registered streams count and delete the device when it
|
/* Decrement the registered streams count and delete the device when it
|
||||||
* reaches zero.
|
* reaches zero.
|
||||||
*/
|
*/
|
||||||
|
@ -1682,7 +1706,7 @@ static int uvc_register_video(struct uvc_device *dev,
|
||||||
* unregistered before the reference is released, so we don't need to
|
* unregistered before the reference is released, so we don't need to
|
||||||
* get another one.
|
* get another one.
|
||||||
*/
|
*/
|
||||||
vdev->parent = &dev->intf->dev;
|
vdev->v4l2_dev = &dev->vdev;
|
||||||
vdev->fops = &uvc_fops;
|
vdev->fops = &uvc_fops;
|
||||||
vdev->release = uvc_release;
|
vdev->release = uvc_release;
|
||||||
strlcpy(vdev->name, dev->name, sizeof vdev->name);
|
strlcpy(vdev->name, dev->name, sizeof vdev->name);
|
||||||
|
@ -1731,6 +1755,8 @@ static int uvc_register_terms(struct uvc_device *dev,
|
||||||
ret = uvc_register_video(dev, stream);
|
ret = uvc_register_video(dev, stream);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
term->vdev = stream->vdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1745,6 +1771,14 @@ static int uvc_register_chains(struct uvc_device *dev)
|
||||||
ret = uvc_register_terms(dev, chain);
|
ret = uvc_register_terms(dev, chain);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
#ifdef CONFIG_MEDIA_CONTROLLER
|
||||||
|
ret = uvc_mc_register_entities(chain);
|
||||||
|
if (ret < 0) {
|
||||||
|
uvc_printk(KERN_INFO, "Failed to register entites "
|
||||||
|
"(%d).\n", ret);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1814,6 +1848,24 @@ static int uvc_probe(struct usb_interface *intf,
|
||||||
"linux-uvc-devel mailing list.\n");
|
"linux-uvc-devel mailing list.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Register the media and V4L2 devices. */
|
||||||
|
#ifdef CONFIG_MEDIA_CONTROLLER
|
||||||
|
dev->mdev.dev = &intf->dev;
|
||||||
|
strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
|
||||||
|
if (udev->serial)
|
||||||
|
strlcpy(dev->mdev.serial, udev->serial,
|
||||||
|
sizeof(dev->mdev.serial));
|
||||||
|
strcpy(dev->mdev.bus_info, udev->devpath);
|
||||||
|
dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
|
||||||
|
dev->mdev.driver_version = DRIVER_VERSION_NUMBER;
|
||||||
|
if (media_device_register(&dev->mdev) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
dev->vdev.mdev = &dev->mdev;
|
||||||
|
#endif
|
||||||
|
if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
/* Initialize controls. */
|
/* Initialize controls. */
|
||||||
if (uvc_ctrl_init_device(dev) < 0)
|
if (uvc_ctrl_init_device(dev) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -1822,7 +1874,7 @@ static int uvc_probe(struct usb_interface *intf,
|
||||||
if (uvc_scan_device(dev) < 0)
|
if (uvc_scan_device(dev) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Register video devices. */
|
/* Register video device nodes. */
|
||||||
if (uvc_register_chains(dev) < 0)
|
if (uvc_register_chains(dev) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* uvc_entity.c -- USB Video Class driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005-2011
|
||||||
|
* Laurent Pinchart (laurent.pinchart@ideasonboard.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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
|
||||||
|
#include <media/v4l2-common.h>
|
||||||
|
|
||||||
|
#include "uvcvideo.h"
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------
|
||||||
|
* Video subdevices registration and unregistration
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int uvc_mc_register_entity(struct uvc_video_chain *chain,
|
||||||
|
struct uvc_entity *entity)
|
||||||
|
{
|
||||||
|
const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
|
||||||
|
struct uvc_entity *remote;
|
||||||
|
unsigned int i;
|
||||||
|
u8 remote_pad;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
for (i = 0; i < entity->num_pads; ++i) {
|
||||||
|
struct media_entity *source;
|
||||||
|
struct media_entity *sink;
|
||||||
|
|
||||||
|
if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]);
|
||||||
|
if (remote == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
|
||||||
|
? &remote->vdev->entity : &remote->subdev.entity;
|
||||||
|
sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING)
|
||||||
|
? &entity->vdev->entity : &entity->subdev.entity;
|
||||||
|
|
||||||
|
remote_pad = remote->num_pads - 1;
|
||||||
|
ret = media_entity_create_link(source, remote_pad,
|
||||||
|
sink, i, flags);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING)
|
||||||
|
ret = v4l2_device_register_subdev(&chain->dev->vdev,
|
||||||
|
&entity->subdev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct v4l2_subdev_ops uvc_subdev_ops = {
|
||||||
|
};
|
||||||
|
|
||||||
|
void uvc_mc_cleanup_entity(struct uvc_entity *entity)
|
||||||
|
{
|
||||||
|
if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING)
|
||||||
|
media_entity_cleanup(&entity->subdev.entity);
|
||||||
|
else if (entity->vdev != NULL)
|
||||||
|
media_entity_cleanup(&entity->vdev->entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uvc_mc_init_entity(struct uvc_entity *entity)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
|
||||||
|
v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops);
|
||||||
|
strlcpy(entity->subdev.name, entity->name,
|
||||||
|
sizeof(entity->subdev.name));
|
||||||
|
|
||||||
|
ret = media_entity_init(&entity->subdev.entity,
|
||||||
|
entity->num_pads, entity->pads, 0);
|
||||||
|
} else
|
||||||
|
ret = media_entity_init(&entity->vdev->entity,
|
||||||
|
entity->num_pads, entity->pads, 0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uvc_mc_register_entities(struct uvc_video_chain *chain)
|
||||||
|
{
|
||||||
|
struct uvc_entity *entity;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
list_for_each_entry(entity, &chain->entities, chain) {
|
||||||
|
ret = uvc_mc_init_entity(entity);
|
||||||
|
if (ret < 0) {
|
||||||
|
uvc_printk(KERN_INFO, "Failed to initialize entity for "
|
||||||
|
"entity %u\n", entity->id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry(entity, &chain->entities, chain) {
|
||||||
|
ret = uvc_mc_register_entity(chain, entity);
|
||||||
|
if (ret < 0) {
|
||||||
|
uvc_printk(KERN_INFO, "Failed to register entity for "
|
||||||
|
"entity %u\n", entity->id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -98,8 +98,11 @@ struct uvc_xu_control {
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
|
#include <linux/usb.h>
|
||||||
#include <linux/usb/video.h>
|
#include <linux/usb/video.h>
|
||||||
#include <linux/uvcvideo.h>
|
#include <linux/uvcvideo.h>
|
||||||
|
#include <media/media-device.h>
|
||||||
|
#include <media/v4l2-device.h>
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------
|
||||||
* UVC constants
|
* UVC constants
|
||||||
|
@ -301,6 +304,13 @@ struct uvc_entity {
|
||||||
__u16 type;
|
__u16 type;
|
||||||
char name[64];
|
char name[64];
|
||||||
|
|
||||||
|
/* Media controller-related fields. */
|
||||||
|
struct video_device *vdev;
|
||||||
|
struct v4l2_subdev subdev;
|
||||||
|
unsigned int num_pads;
|
||||||
|
unsigned int num_links;
|
||||||
|
struct media_pad *pads;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
__u16 wObjectiveFocalLengthMin;
|
__u16 wObjectiveFocalLengthMin;
|
||||||
|
@ -504,6 +514,10 @@ struct uvc_device {
|
||||||
atomic_t nmappings;
|
atomic_t nmappings;
|
||||||
|
|
||||||
/* Video control interface */
|
/* Video control interface */
|
||||||
|
#ifdef CONFIG_MEDIA_CONTROLLER
|
||||||
|
struct media_device mdev;
|
||||||
|
#endif
|
||||||
|
struct v4l2_device vdev;
|
||||||
__u16 uvc_version;
|
__u16 uvc_version;
|
||||||
__u32 clock_frequency;
|
__u32 clock_frequency;
|
||||||
|
|
||||||
|
@ -583,6 +597,8 @@ extern unsigned int uvc_timeout_param;
|
||||||
/* Core driver */
|
/* Core driver */
|
||||||
extern struct uvc_driver uvc_driver;
|
extern struct uvc_driver uvc_driver;
|
||||||
|
|
||||||
|
extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
|
||||||
|
|
||||||
/* Video buffers queue management. */
|
/* Video buffers queue management. */
|
||||||
extern void uvc_queue_init(struct uvc_video_queue *queue,
|
extern void uvc_queue_init(struct uvc_video_queue *queue,
|
||||||
enum v4l2_buf_type type, int drop_corrupted);
|
enum v4l2_buf_type type, int drop_corrupted);
|
||||||
|
@ -616,6 +632,10 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
|
||||||
/* V4L2 interface */
|
/* V4L2 interface */
|
||||||
extern const struct v4l2_file_operations uvc_fops;
|
extern const struct v4l2_file_operations uvc_fops;
|
||||||
|
|
||||||
|
/* Media controller */
|
||||||
|
extern int uvc_mc_register_entities(struct uvc_video_chain *chain);
|
||||||
|
extern void uvc_mc_cleanup_entity(struct uvc_entity *entity);
|
||||||
|
|
||||||
/* Video */
|
/* Video */
|
||||||
extern int uvc_video_init(struct uvc_streaming *stream);
|
extern int uvc_video_init(struct uvc_streaming *stream);
|
||||||
extern int uvc_video_suspend(struct uvc_streaming *stream);
|
extern int uvc_video_suspend(struct uvc_streaming *stream);
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Driver header for M-5MOLS 8M Pixel camera sensor with ISP
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
|
||||||
|
* Author: HeungJun Kim, riverful.kim@samsung.com
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Samsung Electronics Co., Ltd.
|
||||||
|
* Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MEDIA_M5MOLS_H
|
||||||
|
#define MEDIA_M5MOLS_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct m5mols_platform_data - platform data for M-5MOLS driver
|
||||||
|
* @irq: GPIO getting the irq pin of M-5MOLS
|
||||||
|
* @gpio_reset: GPIO driving the reset pin of M-5MOLS
|
||||||
|
* @reset_polarity: active state for gpio_rst pin, 0 or 1
|
||||||
|
* @set_power: an additional callback to the board setup code
|
||||||
|
* to be called after enabling and before disabling
|
||||||
|
* the sensor's supply regulators
|
||||||
|
*/
|
||||||
|
struct m5mols_platform_data {
|
||||||
|
int irq;
|
||||||
|
int gpio_reset;
|
||||||
|
u8 reset_polarity;
|
||||||
|
int (*set_power)(struct device *dev, int on);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* MEDIA_M5MOLS_H */
|
|
@ -4,6 +4,9 @@
|
||||||
#include <dvb_net.h>
|
#include <dvb_net.h>
|
||||||
#include <dvb_frontend.h>
|
#include <dvb_frontend.h>
|
||||||
|
|
||||||
|
#ifndef _VIDEOBUF_DVB_H_
|
||||||
|
#define _VIDEOBUF_DVB_H_
|
||||||
|
|
||||||
struct videobuf_dvb {
|
struct videobuf_dvb {
|
||||||
/* filling that the job of the driver */
|
/* filling that the job of the driver */
|
||||||
char *name;
|
char *name;
|
||||||
|
@ -54,6 +57,7 @@ void videobuf_dvb_dealloc_frontends(struct videobuf_dvb_frontends *f);
|
||||||
struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_frontends *f, int id);
|
struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_frontends *f, int id);
|
||||||
int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p);
|
int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p);
|
||||||
|
|
||||||
|
#endif /* _VIDEOBUF_DVB_H_ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
|
|
Loading…
Reference in New Issue