Hello,
I succesfully got out images reliably. I just the nokia-tree and mixed
up your mt9t031 and Laurent's mt9t001 code. It's just a barebone that
gets images in default size. It's not cleaned up yet, but I post what
I have.
Greetings,
Bastian
2010/12/6 Guennadi Liakhovetski <[email protected]>:
> On Thu, 4 Nov 2010, Laurent Pinchart wrote:
>
>> Hi Bastian,
>
> Hi Bastian, all
>
> Have you or anyone ben successful getting mt9p031 to work with the omap3
> ISP driver? If so - can I have the code? Or even if it never worked -
> could you post the latest version of your driver and platform bindings?
>
> Thanks
> Guennadi
>
>>
>> On Tuesday 02 November 2010 11:31:28 Bastian Hecht wrote:
>> > >> I am the first guy needing a 12 bit-bus?
>> > >
>> > > Yes you are :-) You will need to implement 12 bit support in the ISP
>> > > driver, or start by hacking the sensor driver to report a 10 bit format
>> > > (2 bits will be lost but you should still be able to capture an image).
>> >
>> > Isn't that an "officially" supported procedure to drop the least
>> > significant bits?
>> > You gave me the isp configuration
>> > .bus = { .parallel = {
>> > .data_lane_shift = 1,
>> > ...
>> > that instructs the isp to use 10 of the 12 bits.
>>
>> If you don't need the full 12 bits, sure, that should work.
>>
>> > >> Second thing is, the yavta app now gets stuck while dequeuing a buffer.
>> > >>
>> > >> strace ./yavta -f SGRBG10 -s 2592x1944 -n 4 --capture=4 --skip 3 -F
>> > >> /dev/video2 ...
>> > >> ioctl(3, VIDIOC_QBUF, 0xbec111cc) = 0
>> > >> ioctl(3, VIDIOC_QBUF, 0xbec111cc) = 0
>> > >> ioctl(3, VIDIOC_QBUF, 0xbec111cc) = 0
>> > >> ioctl(3, VIDIOC_QBUF, 0xbec111cc) = 0
>> > >> ioctl(3, VIDIOC_STREAMON, 0xbec11154) = 0
>> > >> ioctl(3, VIDIOC_DQBUF
>> > >>
>> > >> strace gets stuck in mid of this line.
>> >
>> > Somehow the ISP_ENABLE_IRQ register was reset at some point that is
>> > unclear to me. When I put it on again manually yavta succeeds to read
>> > the frames.
>>
>> That's weird. Let me know if you can reproduce the problem.
>>
>> > Unfortunately the image consists of black pixels only. We found out that
>> > the
>> > 2.8V voltage regulator got broken in the course of development - the 1.8V
>> > logic still worked but the ADC did not...
>> >
>> > But the heck - I was never that close :)
>>
>> --
>> Regards,
>>
>> Laurent Pinchart
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-media" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer
> http://www.open-technology.de/
>
/*
* arch/arm/mach-omap2/board-bastix.c
*
* Copyright (C) 2010 Bastian Hecht <[email protected]>
*
* based on
*
* Copyright (C) 2008 Nokia Corporation
*
* Contact: Sakari Ailus <[email protected]>
* Tuukka Toivonen <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/i2c.h>
#include <linux/i2c/twl.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/platform_device.h>
#include <linux/videodev2.h>
#include <asm/gpio.h>
#include <plat/control.h>
#include "../../../drivers/media/video/isp/isp.h"
#include "../../../drivers/media/video/isp/ispreg.h"
#include <media/mt9t001.h>
#include "devices.h"
#define GPIO_DIR_OUTPUT 0
// IGEP CAM BUS NUM
#define BASTIX_CAM_I2C_BUS_NUM 2
static int __init cam_init(void)
{
return 0;
}
static int bastix_configure_interface(struct v4l2_subdev *subdev,
int width, int height)
{
struct isp_device *isp = v4l2_dev_to_isp_device(subdev->v4l2_dev);
//isp_set_pixel_clock(isp, 0);
return 0;
}
static struct mt9t001_platform_data bastix_mt9p031_platform_data = {
.clk_pol = 0,
};
static struct i2c_board_info bastix_camera_i2c_devices[] = {
{
I2C_BOARD_INFO(MT9P031_NAME, MT9P031_I2C_ADDR),
.platform_data = &bastix_mt9p031_platform_data,
},
};
static struct v4l2_subdev_i2c_board_info bastix_camera_mt9p031[] = {
{
.board_info = &bastix_camera_i2c_devices[0],
.i2c_adapter_id = BASTIX_CAM_I2C_BUS_NUM,
},
{ NULL, 0, },
};
static struct isp_v4l2_subdevs_group bastix_camera_subdevs[] = {
{
.subdevs = bastix_camera_mt9p031,
.interface = ISP_INTERFACE_PARALLEL,
.bus = { .parallel = {
.data_lane_shift = 1,
.clk_pol = 0,
.bridge = ISPCTRL_PAR_BRIDGE_DISABLE,
} },
},
{ NULL, 0, },
};
static struct isp_platform_data bastix_isp_platform_data = {
.subdevs = bastix_camera_subdevs,
};
static int __init bastix_camera_init(void)
{
int err;
printk(KERN_ALERT "address of isp_platform_data in boardconfig: %x\n", &bastix_isp_platform_data);
err = cam_init();
if (err)
return err;
omap3isp_device.dev.platform_data = &bastix_isp_platform_data;
return platform_device_register(&omap3isp_device);
}
static void __exit bastix_camera_exit(void)
{
platform_device_unregister(&omap3isp_device);
}
module_init(bastix_camera_init);
module_exit(bastix_camera_exit);
MODULE_LICENSE("GPL");
/*
* Copyright (C) 2009 Integration Software and Electronic Engineering.
*
* Modified from mach-omap2/board-generic.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <plat/board.h>
#include <plat/common.h>
#include <plat/gpmc.h>
#include <plat/usb.h>
#include <plat/display.h>
#include <plat/onenand.h>
#include "mux.h"
#include "hsmmc.h"
#include "sdram-numonyx-m65kxxxxam.h"
#define IGEP2_SMSC911X_CS 5
#define IGEP2_SMSC911X_GPIO 176
#define IGEP2_GPIO_USBH_NRESET 24
#define IGEP2_GPIO_LED0_GREEN 26
#define IGEP2_GPIO_LED0_RED 27
#define IGEP2_GPIO_LED1_RED 28
#define IGEP2_GPIO_DVI_PUP 170
#define IGEP2_GPIO_WIFI_NPD 94
#define IGEP2_GPIO_WIFI_NRESET 95
#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
#define ONENAND_MAP 0x20000000
/* NAND04GR4E1A ( x2 Flash built-in COMBO POP MEMORY )
* Since the device is equipped with two DataRAMs, and two-plane NAND
* Flash memory array, these two component enables simultaneous program
* of 4KiB. Plane1 has only even blocks such as block0, block2, block4
* while Plane2 has only odd blocks such as block1, block3, block5.
* So MTD regards it as 4KiB page size and 256KiB block size 64*(2*2048)
*/
static struct mtd_partition igep2_onenand_partitions[] = {
{
.name = "X-Loader",
.offset = 0,
.size = 2 * (64*(2*2048))
},
{
.name = "U-Boot",
.offset = MTDPART_OFS_APPEND,
.size = 6 * (64*(2*2048)),
},
{
.name = "Environment",
.offset = MTDPART_OFS_APPEND,
.size = 2 * (64*(2*2048)),
},
{
.name = "Kernel",
.offset = MTDPART_OFS_APPEND,
.size = 12 * (64*(2*2048)),
},
{
.name = "File System",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
},
};
static int igep2_onenand_setup(void __iomem *onenand_base, int freq)
{
/* nothing is required to be setup for onenand as of now */
return 0;
}
static struct omap_onenand_platform_data igep2_onenand_data = {
.parts = igep2_onenand_partitions,
.nr_parts = ARRAY_SIZE(igep2_onenand_partitions),
.onenand_setup = igep2_onenand_setup,
.dma_channel = -1, /* disable DMA in OMAP OneNAND driver */
};
static struct platform_device igep2_onenand_device = {
.name = "omap2-onenand",
.id = -1,
.dev = {
.platform_data = &igep2_onenand_data,
},
};
void __init igep2_flash_init(void)
{
u8 cs = 0;
u8 onenandcs = GPMC_CS_NUM + 1;
while (cs < GPMC_CS_NUM) {
u32 ret = 0;
ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
/* Check if NAND/oneNAND is configured */
if ((ret & 0xC00) == 0x800)
/* NAND found */
pr_err("IGEP v2: Unsupported NAND found\n");
else {
ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
if ((ret & 0x3F) == (ONENAND_MAP >> 24))
/* ONENAND found */
onenandcs = cs;
}
cs++;
}
if (onenandcs > GPMC_CS_NUM) {
pr_err("IGEP v2: Unable to find configuration in GPMC\n");
return;
}
if (onenandcs < GPMC_CS_NUM) {
igep2_onenand_data.cs = onenandcs;
if (platform_device_register(&igep2_onenand_device) < 0)
pr_err("IGEP v2: Unable to register OneNAND device\n");
}
}
#else
void __init igep2_flash_init(void) {}
#endif
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
#include <linux/smsc911x.h>
static struct smsc911x_platform_config igep2_smsc911x_config = {
.irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
.irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
.flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS ,
.phy_interface = PHY_INTERFACE_MODE_MII,
};
static struct resource igep2_smsc911x_resources[] = {
{
.flags = IORESOURCE_MEM,
},
{
.start = OMAP_GPIO_IRQ(IGEP2_SMSC911X_GPIO),
.end = OMAP_GPIO_IRQ(IGEP2_SMSC911X_GPIO),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
},
};
static struct platform_device igep2_smsc911x_device = {
.name = "smsc911x",
.id = 0,
.num_resources = ARRAY_SIZE(igep2_smsc911x_resources),
.resource = igep2_smsc911x_resources,
.dev = {
.platform_data = &igep2_smsc911x_config,
},
};
static inline void __init igep2_init_smsc911x(void)
{
unsigned long cs_mem_base;
if (gpmc_cs_request(IGEP2_SMSC911X_CS, SZ_16M, &cs_mem_base) < 0) {
pr_err("IGEP v2: Failed request for GPMC mem for smsc911x\n");
gpmc_cs_free(IGEP2_SMSC911X_CS);
return;
}
igep2_smsc911x_resources[0].start = cs_mem_base + 0x0;
igep2_smsc911x_resources[0].end = cs_mem_base + 0xff;
if ((gpio_request(IGEP2_SMSC911X_GPIO, "SMSC911X IRQ") == 0) &&
(gpio_direction_input(IGEP2_SMSC911X_GPIO) == 0)) {
gpio_export(IGEP2_SMSC911X_GPIO, 0);
} else {
pr_err("IGEP v2: Could not obtain gpio for for SMSC911X IRQ\n");
return;
}
platform_device_register(&igep2_smsc911x_device);
}
#else
static inline void __init igep2_init_smsc911x(void) { }
#endif
static struct omap_board_config_kernel igep2_config[] __initdata = {
};
static struct regulator_consumer_supply igep2_vmmc1_supply = {
.supply = "vmmc",
};
static struct regulator_consumer_supply igep2_vmmc2_supply = {
.supply = "vmmc",
};
/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
static struct regulator_init_data igep2_vmmc1 = {
.constraints = {
.min_uV = 1850000,
.max_uV = 3150000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &igep2_vmmc1_supply,
};
/* VMMC2 for OMAP VDD_MMC2 (i/o) and MMC2 WIFI */
static struct regulator_init_data igep2_vmmc2 = {
.constraints = {
.min_uV = 1850000,
.max_uV = 3150000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &igep2_vmmc2_supply,
};
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
{
.mmc = 2,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
{} /* Terminator */
};
static int igep2_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
/* gpio + 0 is "mmc0_cd" (input/IRQ) */
mmc[0].gpio_cd = gpio + 0;
omap2_hsmmc_init(mmc);
/* link regulators to MMC adapters ... we "know" the
* regulators will be set up only *after* we return.
*/
igep2_vmmc1_supply.dev = mmc[0].dev;
igep2_vmmc2_supply.dev = mmc[1].dev;
return 0;
};
static struct twl4030_gpio_platform_data igep2_gpio_data = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
.use_leds = false,
.setup = igep2_twl_gpio_setup,
};
static struct twl4030_usb_data igep2_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
static int igep2_enable_dvi(struct omap_dss_device *dssdev)
{
gpio_direction_output(IGEP2_GPIO_DVI_PUP, 1);
return 0;
}
static void igep2_disable_dvi(struct omap_dss_device *dssdev)
{
gpio_direction_output(IGEP2_GPIO_DVI_PUP, 0);
}
static struct omap_dss_device igep2_dvi_device = {
.type = OMAP_DISPLAY_TYPE_DPI,
.name = "dvi",
.driver_name = "generic_panel",
.phy.dpi.data_lines = 24,
.platform_enable = igep2_enable_dvi,
.platform_disable = igep2_disable_dvi,
};
static struct omap_dss_device *igep2_dss_devices[] = {
&igep2_dvi_device
};
static struct omap_dss_board_info igep2_dss_data = {
.num_devices = ARRAY_SIZE(igep2_dss_devices),
.devices = igep2_dss_devices,
.default_device = &igep2_dvi_device,
};
static struct platform_device igep2_dss_device = {
.name = "omapdss",
.id = -1,
.dev = {
.platform_data = &igep2_dss_data,
},
};
static struct regulator_consumer_supply igep2_vpll2_supply = {
.supply = "vdds_dsi",
.dev = &igep2_dss_device.dev,
};
static struct regulator_init_data igep2_vpll2 = {
.constraints = {
.name = "VDVI",
.min_uV = 1800000,
.max_uV = 1800000,
.apply_uV = true,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &igep2_vpll2_supply,
};
static void __init igep2_display_init(void)
{
if (gpio_request(IGEP2_GPIO_DVI_PUP, "GPIO_DVI_PUP") &&
gpio_direction_output(IGEP2_GPIO_DVI_PUP, 1))
pr_err("IGEP v2: Could not obtain gpio GPIO_DVI_PUP\n");
}
#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
#include <linux/leds.h>
static struct gpio_led igep2_gpio_leds[] = {
{
.name = "led0:red",
.gpio = IGEP2_GPIO_LED0_RED,
},
{
.name = "led0:green",
.default_trigger = "heartbeat",
.gpio = IGEP2_GPIO_LED0_GREEN,
},
{
.name = "led1:red",
.gpio = IGEP2_GPIO_LED1_RED,
},
};
static struct gpio_led_platform_data igep2_led_pdata = {
.leds = igep2_gpio_leds,
.num_leds = ARRAY_SIZE(igep2_gpio_leds),
};
static struct platform_device igep2_led_device = {
.name = "leds-gpio",
.id = -1,
.dev = {
.platform_data = &igep2_led_pdata,
},
};
static void __init igep2_init_led(void)
{
platform_device_register(&igep2_led_device);
}
#else
static inline void igep2_init_led(void) {}
#endif
static struct platform_device *igep2_devices[] __initdata = {
&igep2_dss_device,
};
static void __init igep2_init_irq(void)
{
omap_board_config = igep2_config;
omap_board_config_size = ARRAY_SIZE(igep2_config);
omap2_init_common_hw(m65kxxxxam_sdrc_params, m65kxxxxam_sdrc_params);
omap_init_irq();
omap_gpio_init();
}
static struct twl4030_codec_audio_data igep2_audio_data = {
.audio_mclk = 26000000,
};
static struct twl4030_codec_data igep2_codec_data = {
.audio_mclk = 26000000,
.audio = &igep2_audio_data,
};
static struct twl4030_platform_data igep2_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.usb = &igep2_usb_data,
.codec = &igep2_codec_data,
.gpio = &igep2_gpio_data,
.vmmc1 = &igep2_vmmc1,
.vmmc2 = &igep2_vmmc2,
.vpll2 = &igep2_vpll2,
};
static struct i2c_board_info __initdata igep2_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
.flags = I2C_CLIENT_WAKE,
.irq = INT_34XX_SYS_NIRQ,
.platform_data = &igep2_twldata,
},
};
static int __init igep2_i2c_init(void)
{
omap_register_i2c_bus(1, 2600, igep2_i2c_boardinfo,
ARRAY_SIZE(igep2_i2c_boardinfo));
/* register camera i2c bus */
omap_register_i2c_bus(2, 100, NULL, 0);
/* Bus 3 is attached to the DVI port where devices like the pico DLP
* projector don't work reliably with 400kHz */
omap_register_i2c_bus(3, 100, NULL, 0);
return 0;
}
static struct omap_musb_board_data musb_board_data = {
.interface_type = MUSB_INTERFACE_ULPI,
.mode = MUSB_OTG,
.power = 100,
};
static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
.port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
.phy_reset = true,
.reset_gpio_port[0] = IGEP2_GPIO_USBH_NRESET,
.reset_gpio_port[1] = -EINVAL,
.reset_gpio_port[2] = -EINVAL,
};
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
// CAM_I2C2
OMAP3_MUX(I2C2_SCL, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE),
OMAP3_MUX(I2C2_SDA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE),
// CAM_HS in down dis
// CAM_VS in down dis
OMAP3_MUX(CAM_HS, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
OMAP3_MUX(CAM_VS, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
// CAM_D* in down dis
OMAP3_MUX(CAM_D0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
OMAP3_MUX(CAM_D1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
OMAP3_MUX(CAM_D2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
OMAP3_MUX(CAM_D3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
OMAP3_MUX(CAM_D4, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
OMAP3_MUX(CAM_D5, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
OMAP3_MUX(CAM_D6, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
OMAP3_MUX(CAM_D7, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
OMAP3_MUX(CAM_D8, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
OMAP3_MUX(CAM_D9, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
OMAP3_MUX(CAM_D10, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
OMAP3_MUX(CAM_D11, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
// CAM_STROBE out GPIO down goes to aptina_trigger
OMAP3_MUX(CAM_STROBE, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
OMAP3_MUX(CAM_PCLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
// CAM_RESET
// OMAP3_MUX(CSI2_DX0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
// OMAP3_MUX(CSI2_DY0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
// OMAP3_MUX(CSI2_DX1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
// OMAP3_MUX(CSI2_DY1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN | OMAP_PIN_OFF_INPUT_PULLDOWN | OMAP_PIN_OFF_WAKEUPENABLE),
/*
CAM_WEN NC
CAM_FLD NC
CAM_PDN NC
CAM_XCLKB NC
CAM_XCLKA passt
CAM_PCLK passt
*/
/*
// GO SPI!!!
OMAP3_MUX(MCBSP1_CLKR, OMAP_MUX_MODE2 | OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE),
OMAP3_MUX(MCBSP1_DR, OMAP_MUX_MODE2 | OMAP_PIN_INPUT),
OMAP3_MUX(MCBSP1_FSX, OMAP_MUX_MODE2 | OMAP_PIN_OUTPUT),
OMAP3_MUX(MCBSP1_DX, OMAP_MUX_MODE2 | OMAP_PIN_OUTPUT),
MCBSP1_CLKR, -> clk
MCBSP1_DR -> somi
MCBSP1_FSX -> cs0
MCBSP1_DX, -> simo
*/
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
#else
#error "BUT I WANNA CONFIGURE MY GPIOS!!! -Basti"
#endif
static void __init igep2_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
printk(KERN_ALERT "muxing done\n");
igep2_i2c_init();
platform_add_devices(igep2_devices, ARRAY_SIZE(igep2_devices));
omap_serial_init();
usb_musb_init(&musb_board_data);
usb_ehci_init(&ehci_pdata);
igep2_flash_init();
igep2_init_led();
igep2_display_init();
igep2_init_smsc911x();
/* GPIO userspace leds */
#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
if ((gpio_request(IGEP2_GPIO_LED0_RED, "led0:red") == 0) &&
(gpio_direction_output(IGEP2_GPIO_LED0_RED, 1) == 0)) {
gpio_export(IGEP2_GPIO_LED0_RED, 0);
gpio_set_value(IGEP2_GPIO_LED0_RED, 0);
} else
pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_RED\n");
if ((gpio_request(IGEP2_GPIO_LED0_GREEN, "led0:green") == 0) &&
(gpio_direction_output(IGEP2_GPIO_LED0_GREEN, 1) == 0)) {
gpio_export(IGEP2_GPIO_LED0_GREEN, 0);
gpio_set_value(IGEP2_GPIO_LED0_GREEN, 0);
} else
pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_GREEN\n");
if ((gpio_request(IGEP2_GPIO_LED1_RED, "led1:red") == 0) &&
(gpio_direction_output(IGEP2_GPIO_LED1_RED, 1) == 0)) {
gpio_export(IGEP2_GPIO_LED1_RED, 0);
gpio_set_value(IGEP2_GPIO_LED1_RED, 0);
} else
pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_RED\n");
#endif
/* GPIO W-LAN + Bluetooth combo module */
if ((gpio_request(IGEP2_GPIO_WIFI_NPD, "GPIO_WIFI_NPD") == 0) &&
(gpio_direction_output(IGEP2_GPIO_WIFI_NPD, 1) == 0)) {
gpio_export(IGEP2_GPIO_WIFI_NPD, 0);
/* gpio_set_value(IGEP2_GPIO_WIFI_NPD, 0); */
} else
pr_warning("IGEP v2: Could not obtain gpio GPIO_WIFI_NPD\n");
if ((gpio_request(IGEP2_GPIO_WIFI_NRESET, "GPIO_WIFI_NRESET") == 0) &&
(gpio_direction_output(IGEP2_GPIO_WIFI_NRESET, 1) == 0)) {
gpio_export(IGEP2_GPIO_WIFI_NRESET, 0);
gpio_set_value(IGEP2_GPIO_WIFI_NRESET, 0);
udelay(10);
gpio_set_value(IGEP2_GPIO_WIFI_NRESET, 1);
} else
pr_warning("IGEP v2: Could not obtain gpio GPIO_WIFI_NRESET\n");
}
static void __init igep2_map_io(void)
{
omap2_set_globals_343x();
omap34xx_map_common_io();
}
MACHINE_START(IGEP0020, "IGEP v2 board")
.phys_io = 0x48000000,
.io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = igep2_map_io,
.init_irq = igep2_init_irq,
.init_machine = igep2_init,
.timer = &omap_timer,
MACHINE_END
/*
* Driver for MT9P031 CMOS Image Sensor from Micron
*
* Copyright (C) 2010, Bastian Hecht <[email protected]>
*
* Based on the MT9T001 and MT9T031 drivers from
*
* Guennadi Liakhovetski, DENX Software Engineering <[email protected]>
* Laurent Pinchart <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include "../../../drivers/media/video/isp/isp.h"
#include "../../../drivers/media/video/isp/ispreg.h"
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/log2.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
//#include <media/soc_camera.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-device.h>
#include "isp/isp.h"
#include <linux/debugfs.h>
/*
* mt9p031 i2c address 0x5d (0xBA read, 0xBB write) same as mt9t031
* The platform has to define i2c_board_info and link to it from
* struct soc_camera_link
*/
/* mt9p031 selected register addresses */
#define MT9P031_CHIP_VERSION 0x00
#define MT9P031_ROW_START 0x01
#define MT9P031_COLUMN_START 0x02
#define MT9P031_WINDOW_HEIGHT 0x03
#define MT9P031_WINDOW_WIDTH 0x04
#define MT9P031_HORIZONTAL_BLANKING 0x05
#define MT9P031_VERTICAL_BLANKING 0x06
#define MT9P031_OUTPUT_CONTROL 0x07
#define MT9P031_SHUTTER_WIDTH_UPPER 0x08
#define MT9P031_SHUTTER_WIDTH 0x09
#define MT9P031_PIXEL_CLOCK_CONTROL 0x0a
#define MT9P031_FRAME_RESTART 0x0b
#define MT9P031_SHUTTER_DELAY 0x0c
#define MT9P031_RESET 0x0d
#define MT9P031_READ_MODE_1 0x1e
#define MT9P031_READ_MODE_2 0x20
#define MT9P031_ROW_ADDRESS_MODE 0x22
#define MT9P031_COLUMN_ADDRESS_MODE 0x23
#define MT9P031_GLOBAL_GAIN 0x35
#define MT9P031_TEST_ENABLE 0xa0
#define MT9P031_TEST_GREEN 0xa1
#define MT9P031_TEST_RED 0xa2
#define MT9P031_TEST_BLUE 0xa3
//#define MT9T031_CHIP_ENABLE 0xF8 // PDN is pin signal. no i2c register
#define MT9P031_MAX_HEIGHT 1944 // adapted
#define MT9P031_MAX_WIDTH 2592 // adapted
#define MT9P031_MIN_HEIGHT 2 // could be 0
#define MT9P031_MIN_WIDTH 18 // could be 0
#define MT9P031_HORIZONTAL_BLANK 0 // adapted R0x05
#define MT9P031_VERTICAL_BLANK 25 // adapted R0x06
#define MT9P031_COLUMN_SKIP 16 // adapted
#define MT9P031_ROW_SKIP 54 // adapted
#define MT9P031_CHIP_VERSION_VALUE 0x1801
#define MT9P031_XCLK_RATE 8*1000*1000
/*
#define MT9T031_BUS_PARAM (SOCAM_PCLK_SAMPLE_RISING | \
SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH | \
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \
SOCAM_MASTER | SOCAM_DATAWIDTH_10)
*/
void isp_print_status(struct isp_device *isp);
void ispccdc_print_status(struct isp_ccdc_device *ccdc);
int isp_reset(struct isp_device *isp);
struct mt9p031 {
struct v4l2_subdev subdev;
struct media_entity_pad pad;
struct v4l2_mbus_framefmt format;
struct v4l2_rect rect; /* Sensor window */
int model; /* V4L2_IDENT_MT9P031* codes from v4l2-chip-ident.h */
u16 xskip;
u16 yskip;
unsigned int gain;
unsigned short y_skip_top; /* Lines to skip at the top */
unsigned int exposure;
unsigned char autoexposure;
u8 reg_debug_nr;
u16 reg_debug_value;
};
static struct mt9p031 *to_mt9p031(const struct i2c_client *client)
{
return container_of(i2c_get_clientdata(client), struct mt9p031, subdev);
}
static int reg_read(struct i2c_client *client, const u8 reg)
{
s32 data = i2c_smbus_read_word_data(client, reg);
return data < 0 ? data : swab16(data);
}
static int reg_write(struct i2c_client *client, const u8 reg,
const u16 data)
{
return i2c_smbus_write_word_data(client, reg, swab16(data));
}
static int reg_set(struct i2c_client *client, const u8 reg,
const u16 data)
{
int ret;
ret = reg_read(client, reg);
if (ret < 0)
return ret;
return reg_write(client, reg, ret | data);
}
static int reg_clear(struct i2c_client *client, const u8 reg,
const u16 data)
{
int ret;
ret = reg_read(client, reg);
if (ret < 0)
return ret;
return reg_write(client, reg, ret & ~data);
}
static int set_shutter(struct i2c_client *client, const u32 data)
{
int ret;
ret = reg_write(client, MT9P031_SHUTTER_WIDTH_UPPER, data >> 16);
if (ret >= 0)
ret = reg_write(client, MT9P031_SHUTTER_WIDTH, data & 0xffff);
return ret;
}
static int get_shutter(struct i2c_client *client, u32 *data)
{
int ret;
ret = reg_read(client, MT9P031_SHUTTER_WIDTH_UPPER);
*data = ret << 16;
if (ret >= 0)
ret = reg_read(client, MT9P031_SHUTTER_WIDTH);
*data |= ret & 0xffff;
return ret < 0 ? ret : 0;
}
static int mt9p031_idle(struct i2c_client *client)
{
int ret;
printk(KERN_ALERT "ignoring chip reset\n");
return 0;
/* Disable chip output, synchronous option update */
ret = reg_write(client, MT9P031_RESET, 1);
if (ret >= 0)
ret = reg_write(client, MT9P031_RESET, 0);
if (ret >= 0)
ret = reg_clear(client, MT9P031_OUTPUT_CONTROL, 2);
return ret >= 0 ? 0 : -EIO;
}
///////////////////////////////////////////////////////////////////////////////// STUB
static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_pad_mbus_code_enum *code)
{
printk(KERN_ALERT "pad_op 0\n");
return 0;
}
static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_frame_size_enum *fse)
{
printk(KERN_ALERT "pad_op 1\n");
return 0;
}
static int mt9t001_get_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh, unsigned int pad,
struct v4l2_mbus_framefmt *format,
enum v4l2_subdev_format which)
{
int reg;
struct i2c_client *client = v4l2_get_subdevdata(subdev);
struct mt9p031 *mt9p031 = to_mt9p031(client);
*format = mt9p031->format;
printk(KERN_ALERT "pad_op 4\n");
struct isp_device *isp = v4l2_dev_to_isp_device(mt9p031->subdev.v4l2_dev);
isp_print_status(isp);
ispccdc_print_status(&isp->isp_ccdc);
//printk(KERN_ALERT "turning on test pattern\n");
//reg_write(client, MT9P031_TEST_ENABLE, 1 );
//reg_write(client, MT9P031_TEST_GREEN, 4095);
//reg_write(client, MT9P031_TEST_RED, 1000);
//reg_write(client, MT9P031_TEST_BLUE, 100);
//reg = reg_read(client, MT9P031_OUTPUT_CONTROL);
//reg |= 2; // chip enable
//reg_write(client, MT9P031_OUTPUT_CONTROL, reg);
return 0;
}
static int mt9t001_set_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh, unsigned int pad,
struct v4l2_mbus_framefmt *format,
enum v4l2_subdev_format which)
{
printk(KERN_ALERT "pad_op 5\n");
return 0;
}
static int mt9t001_get_crop(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_pad_crop *crop)
{
printk(KERN_ALERT "pad_op 6\n");
return 0;
}
static int mt9t001_set_crop(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_pad_crop *crop)
{
printk(KERN_ALERT "pad_op 7\n");
return 0;
}
///////////////////////////////////////////////////////////////////////////////// END STUB
static int mt9p031_s_stream(struct v4l2_subdev *sd, int enable)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
printk(KERN_ALERT "s_stream is it! enable: %d\n", enable);
return 0;
if (enable)
/* Switch to master "normal" mode */
ret = reg_set(client, MT9P031_OUTPUT_CONTROL, 2);
else
/* Stop sensor readout */
ret = reg_clear(client, MT9P031_OUTPUT_CONTROL, 2);
if (ret < 0)
return -EIO;
return 0;
}
enum {
MT9P031_CTRL_VFLIP,
MT9P031_CTRL_HFLIP,
MT9P031_CTRL_GAIN,
MT9P031_CTRL_EXPOSURE,
MT9P031_CTRL_EXPOSURE_AUTO,
};
static const struct v4l2_queryctrl mt9p031_controls[] = {
[MT9P031_CTRL_VFLIP] = {
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Flip Vertically",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
[MT9P031_CTRL_HFLIP] = {
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Flip Horizontally",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
[MT9P031_CTRL_GAIN] = {
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
.minimum = 0,
.maximum = 127,
.step = 1,
.default_value = 64,
.flags = V4L2_CTRL_FLAG_SLIDER,
},
[MT9P031_CTRL_EXPOSURE] = {
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Exposure",
.minimum = 1,
.maximum = 255,
.step = 1,
.default_value = 255,
.flags = V4L2_CTRL_FLAG_SLIDER,
},
[MT9P031_CTRL_EXPOSURE_AUTO] = {
.id = V4L2_CID_EXPOSURE_AUTO,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Automatic Exposure",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1,
}
};
static int mt9p031_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9p031 *mt9p031 = to_mt9p031(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
if (id->match.addr != client->addr)
return -ENODEV;
id->ident = mt9p031->model;
id->revision = 0;
return 0;
}
static int mt9p031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9p031 *mt9p031 = to_mt9p031(client);
int data;
printk(KERN_ALERT "mt g_ctrl\n");
switch (ctrl->id) {
case V4L2_CID_VFLIP:
data = reg_read(client, MT9P031_READ_MODE_2);
if (data < 0)
return -EIO;
ctrl->value = !!(data & 0x8000);
break;
case V4L2_CID_HFLIP:
data = reg_read(client, MT9P031_READ_MODE_2);
if (data < 0)
return -EIO;
ctrl->value = !!(data & 0x4000);
break;
case V4L2_CID_EXPOSURE_AUTO:
ctrl->value = mt9p031->autoexposure;
break;
case V4L2_CID_GAIN:
ctrl->value = mt9p031->gain;
break;
case V4L2_CID_EXPOSURE:
ctrl->value = mt9p031->exposure;
break;
}
return 0;
}
static int mt9p031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
printk(KERN_ALERT "s_ctrl\n");
return 0;
}
static struct dev_pm_ops mt9p031_dev_pm_ops = {
/*
.runtime_suspend = mt9t031_runtime_suspend,
.runtime_resume = mt9t031_runtime_resume,
*/
};
static struct device_type mt9p031_dev_type = {
.name = "MT9P031",
.pm = &mt9p031_dev_pm_ops,
};
/*
* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one
*/
static int mt9p031_video_probe(struct i2c_client *client)
{
struct mt9p031 *mt9p031 = to_mt9p031(client);
s32 data;
int ret;
//struct isp_device *isp = v4l2_dev_to_isp_device(mt9p031->subdev.v4l2_dev);
//printk(KERN_ALERT "Set up xlck\n");
//isp_set_xclk(isp, MT9P031_XCLK_RATE, 0);
//msleep(100);
/* Enable the chip */
//data = reg_write(client, MT9P031_CHIP_ENABLE, 1);
//dev_dbg(&client->dev, "write: %d\n", data);
/* Read out the chip version register */
data = reg_read(client, MT9P031_CHIP_VERSION);
switch (data) {
case MT9P031_CHIP_VERSION_VALUE:
mt9p031->model = V4L2_IDENT_MT9P031;
break;
default:
dev_err(&client->dev,
"No MT9P031 chip detected, register read %x\n", data);
return -ENODEV;
}
dev_info(&client->dev, "Detected a MT9P031 chip ID %x\n", data);
ret = mt9p031_idle(client);
if (ret < 0)
dev_err(&client->dev, "Failed to initialise the camera\n");
else
dev_info(&client->dev, "reset succesful\n");//vdev->dev.type = &mt9p031_dev_type;
/* mt9t031_idle() has reset the chip to default. */
mt9p031->exposure = 255;
mt9p031->gain = 64;
return ret;
}
static int mt9p031_open(struct v4l2_subdev *subdev, u32 i)
{
printk(KERN_ALERT "mt9p031 open\n");
return 0;
}
static int mt9p031_query_ctrl(struct v4l2_subdev *subdev,
struct v4l2_queryctrl *qc)
{
return 0;
}
static struct v4l2_subdev_core_ops mt9p031_subdev_core_ops = {
.g_ctrl = mt9p031_g_ctrl,
.s_ctrl = mt9p031_s_ctrl,
.g_chip_ident = mt9p031_g_chip_ident,
.init = mt9p031_open,
.queryctrl = mt9p031_query_ctrl,
};
static struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = {
.s_stream = mt9p031_s_stream,
};
static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
.enum_mbus_code = mt9t001_enum_mbus_code,
.enum_frame_size = mt9t001_enum_frame_size,
.get_fmt = mt9t001_get_format,
.set_fmt = mt9t001_set_format,
.get_crop = mt9t001_get_crop,
.set_crop = mt9t001_set_crop,
};
static struct v4l2_subdev_ops mt9p031_subdev_ops = {
.core = &mt9p031_subdev_core_ops,
.video = &mt9p031_subdev_video_ops,
.pad = &mt9p031_subdev_pad_ops,
};
static int debugfs_open(struct inode* node, struct file* filp)
{
printk(KERN_ALERT "debugfs_regs openend\n");
filp->private_data = node->i_private;
return 0;
}
static ssize_t debugfs_read(struct file* filp, char __user* buf, size_t count, loff_t *fpos)
{
int i=0;
int len=0;
int reg;
struct i2c_client *client = filp->private_data;
if(!client)
return 0;
printk(KERN_ALERT "reading debugfs\n");
printk(KERN_ALERT "clientaddr: %x\n", client);
struct mt9p031 *mt9p031 = to_mt9p031(client);
struct isp_device *isp = v4l2_dev_to_isp_device(mt9p031->subdev.v4l2_dev);
isp_print_status(isp);
if(mt9p031->reg_debug_nr)
{
printk(KERN_ALERT "setting reg %x to %x\n", mt9p031->reg_debug_nr, mt9p031->reg_debug_value);
reg_write(client, mt9p031->reg_debug_nr, mt9p031->reg_debug_value);
}
//isp_reset(isp);
for(i=0;i<255 && (len+20) < count; i++)
{
reg = reg_read(client, i);
printk(KERN_ALERT "register %x: %x\n", i, reg);
len+=sprintf(buf+len, "register %x: %x\n", i, reg);
}
filp->private_data = NULL;
return len;
}
static struct file_operations debugfs_fops = {
.open = debugfs_open,
.read = debugfs_read,
};
static int mt9p031_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9p031 *mt9p031;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int ret;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
dev_warn(&adapter->dev,
"I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
return -EIO;
}
mt9p031 = kzalloc(sizeof(struct mt9p031), GFP_KERNEL);
if (!mt9p031)
return -ENOMEM;
mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops);
mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
// struct isp_device *isp = v4l2_dev_to_isp_device(subdev->v4l2_dev);
// isp_set_xclk(isp, 16*1000*1000, ISP_XCLK_A);
mt9p031->y_skip_top = 0;
mt9p031->rect.left = MT9P031_COLUMN_SKIP;
mt9p031->rect.top = MT9P031_ROW_SKIP;
mt9p031->rect.width = MT9P031_MAX_WIDTH;
mt9p031->rect.height = MT9P031_MAX_HEIGHT;
mt9p031->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
mt9p031->format.width = MT9P031_MAX_WIDTH;
mt9p031->format.height = MT9P031_MAX_HEIGHT;
mt9p031->format.field = V4L2_FIELD_NONE;
mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
/*
* Simulated autoexposure. If enabled, we calculate shutter width
* ourselves in the driver based on vertical blanking and frame width
*/
mt9p031->autoexposure = 1;
mt9p031->xskip = 1;
mt9p031->yskip = 1;
mt9p031_idle(client);
ret = mt9p031_video_probe(client);
//mt9p031_disable(client);
if (ret) {
kfree(mt9p031);
return ret;
}
mt9p031->pad.type = MEDIA_PAD_TYPE_OUTPUT;
ret = media_entity_init(&mt9p031->subdev.entity, 1, &mt9p031->pad, 0);
if (ret) {
kfree(mt9p031);
return ret;
}
mode_t mode = S_IRUGO | S_IWUGO;
struct dentry *dir = debugfs_create_dir("mt9p031", NULL);
struct dentry *regs_filp = debugfs_create_file("regs", mode, dir, client, &debugfs_fops);
debugfs_create_u8("reg_nr", mode, dir, &mt9p031->reg_debug_nr);
debugfs_create_u16("reg_value", mode, dir, &mt9p031->reg_debug_value);
printk(KERN_ALERT "clientaddr: %x\n", client);
return ret;
}
static int mt9p031_remove(struct i2c_client *client)
{
printk(KERN_ALERT "removing mt9p031\n");
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct mt9p031 *mt9p031 = to_mt9p031(client);
v4l2_device_unregister_subdev(subdev);
media_entity_cleanup(&subdev->entity);
kfree(mt9p031);
printk(KERN_ALERT "removing done\n");
return 0;
}
static const struct i2c_device_id mt9p031_id[] = {
{ "mt9p031", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mt9p031_id);
static struct i2c_driver mt9p031_i2c_driver = {
.driver = {
.name = "mt9p031",
},
.probe = mt9p031_probe,
.remove = mt9p031_remove,
.id_table = mt9p031_id,
};
static int __init mt9p031_mod_init(void)
{
return i2c_add_driver(&mt9p031_i2c_driver);
}
static void __exit mt9p031_mod_exit(void)
{
i2c_del_driver(&mt9p031_i2c_driver);
}
module_init(mt9p031_mod_init);
module_exit(mt9p031_mod_exit);
MODULE_DESCRIPTION("Micron MT9T031 Camera driver");
MODULE_AUTHOR("Bastian Hecht <[email protected]>");
MODULE_LICENSE("GPL v2");