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 <g.liakhovetski@xxxxxx>: > 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 majordomo@xxxxxxxxxxxxxxx >> 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 <hechtb@xxxxxxxxx> * * based on * * Copyright (C) 2008 Nokia Corporation * * Contact: Sakari Ailus <sakari.ailus@xxxxxxxxx> * Tuukka Toivonen <tuukka.o.toivonen@xxxxxxxxx> * * 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 <hechtb@xxxxxxxxx> * * Based on the MT9T001 and MT9T031 drivers from * * Guennadi Liakhovetski, DENX Software Engineering <lg@xxxxxxx> * Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx> * * 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 <hechtb@xxxxxxxxx>"); MODULE_LICENSE("GPL v2");