On Friday, May 13, 2011 5:25 AM, Ryan Mallon wrote > On 05/12/2011 07:42 PM, Josh Wu wrote: >> This patch is to enable Atmel Image Sensor Interface (ISI) driver support. >> - Using soc-camera framework with videobuf2 dma-contig allocator >> - Supporting video streaming of YUV packed format >> - Tested on AT91SAM9M10G45-EK with OV2640 > Hi Josh, > Thansk for doing this. Overall the patch looks really good. A few > comments below. Hi, Ryan Thank you for the comments. >> >> Signed-off-by: Josh Wu <josh.wu@xxxxxxxxx> >> --- >> base on branch staging/for_v2.6.40 >> >> arch/arm/mach-at91/include/mach/at91_isi.h | 454 ++++++++++++ >> drivers/media/video/Kconfig | 10 + >> drivers/media/video/Makefile | 1 + >> drivers/media/video/atmel-isi.c | 1089 ++++++++++++++++++++++++++++ >> 4 files changed, 1554 insertions(+), 0 deletions(-) >> create mode 100644 arch/arm/mach-at91/include/mach/at91_isi.h >> create mode 100644 drivers/media/video/atmel-isi.c >> [snip] >> + >> +/* Bit manipulation macros */ >> +#define ISI_BIT(name) \ >> + (1 << ISI_##name##_OFFSET) >> +#define ISI_BF(name, value) \ >> + (((value) & ((1 << ISI_##name##_SIZE) - 1)) \ >> + << ISI_##name##_OFFSET) >> +#define ISI_BFEXT(name, value) \ >> + (((value) >> ISI_##name##_OFFSET) \ >> + & ((1 << ISI_##name##_SIZE) - 1)) >> +#define ISI_BFINS(name, value, old) \ >> + (((old) & ~(((1 << ISI_##name##_SIZE) - 1) \ >> + << ISI_##name##_OFFSET))\ >> + | ISI_BF(name, value)) > I really dislike this kind of register access magic. Not sure how others > feel about it. These macros are really ugly. I understand this. So I will try to find a better way (static inline function) to solve this. :) >> +/* Register access macros */ >> +#define isi_readl(port, reg) \ >> + __raw_readl((port)->regs + ISI_##reg) >> +#define isi_writel(port, reg, value) \ >> + __raw_writel((value), (port)->regs + ISI_##reg) > If the token pasting stuff gets dropped then these can be static inline > functions which is preferred. sure, I'll try. >> [snip] >> +#define ISI_GS_2PIX_PER_WORD 0x00 >> +#define ISI_GS_1PIX_PER_WORD 0x01 >> + u8 pixfmt; >> + u8 sfd; >> + u8 sld; >> + u8 thmask; >> +#define ISI_BURST_4_8_16 0x00 >> +#define ISI_BURST_8_16 0x01 >> +#define ISI_BURST_16 0x02 >> + u8 frate; >> +#define ISI_FRATE_DIV_2 0x01 >> +#define ISI_FRATE_DIV_3 0x02 >> +#define ISI_FRATE_DIV_4 0x03 >> +#define ISI_FRATE_DIV_5 0x04 >> +#define ISI_FRATE_DIV_6 0x05 >> +#define ISI_FRATE_DIV_7 0x06 >> +#define ISI_FRATE_DIV_8 0x07 >> +}; > Might need some comments in this structure so that board file writers > know what each of the fields are for. I think this part will be change a little bit. Also I will add the updated comments. >> + >> +#endif /* __AT91_ISI_H__ */ >> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig >> index d61414e..eae6005 100644 >> --- a/drivers/media/video/Kconfig >> +++ b/drivers/media/video/Kconfig >> @@ -80,6 +80,16 @@ menuconfig VIDEO_CAPTURE_DRIVERS >> Some of those devices also supports FM radio. >> >> if VIDEO_CAPTURE_DRIVERS && VIDEO_V4L2 >> +config VIDEO_ATMEL_ISI >> + tristate "ATMEL Image Sensor Interface (ISI) support" >> + depends on VIDEO_DEV && SOC_CAMERA > Depends on AT91/AVR32? I think I will use AT91 >> [snip] >> + >> +#include <media/videobuf2-dma-contig.h> >> +#include <media/soc_camera.h> >> +#include <media/soc_mediabus.h> >> + >> +#define ATMEL_ISI_VERSION KERNEL_VERSION(1, 0, 0) > Do we really need this version? Since we need set a version for v4l2_capability.version in function isi_camera_querycap(). So we use this macro. How about this? static int isi_camera_querycap(struct soc_camera_host *ici, struct v4l2_capability *cap) { strcpy(cap->driver, "atmel-isi"); strcpy(cap->card, "Atmel Image Sensor Interface"); cap->version = KERNEL_VERSION(1, 0, 0); cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING); return 0; } >> +#define MAX_BUFFER_NUMS 32 >> +#define MAX_SUPPORT_WIDTH 2048 >> +#define MAX_SUPPORT_HEIGHT 2048 >> + >> +static unsigned int vid_limit = 16; > This never gets changed so it can become a const/define. The value is > MB, which is not clear from the name, and it gets multiplied out to > bytes in its only usage, so maybe: > #define VID_LIMIT_BYTES (16 * 1024 * 1024) Your code is good. I will change according to your suggestion. >> + >> +enum isi_buffer_state { >> + ISI_BUF_NEEDS_INIT, >> + ISI_BUF_PREPARED, >> +}; > Aren't there v4l2 constants for this already? > VIDEOBUF_NEEDS_INIT, > VIDEOBUF_PREPARED, > Just reuse those. I checked the code, above constants are used in videobuf not videobuf2. So I think I cannot use it. >> + >> +/* Single frame capturing states */ >> +enum { >> + STATE_IDLE = 0, >> + STATE_CAPTURE_READY, >> + STATE_CAPTURE_WAIT_SOF, >> + STATE_CAPTURE_IN_PROGRESS, >> + STATE_CAPTURE_DONE, >> + STATE_CAPTURE_ERROR, >> +}; >> + >> +/* Frame buffer descriptor >> + * Used by the ISI module as a linked list for the DMA controller. >> + */ >> +struct fbd { >> + /* Physical address of the frame buffer */ >> + u32 fb_address; >> +#if defined(CONFIG_ARCH_AT91SAM9G45) ||\ >> + defined(CONFIG_ARCH_AT91SAM9X5) >> + /* DMA Control Register(only in HISI2) */ >> + u32 dma_ctrl; >> +#endif > I wouldn't bother with this ifdef. The memory cost is pretty > insignificant and it makes the code easier to read without it. It also > means you don't need to patch it up whenever a new at91 platform with > isi dma support appears. I will remove this #if. It is very disappointed to add some ARCH macro every time when any new platform support ISI added. >> + /* Physical address of the next fbd */ >> + u32 next_fbd_address; >> +}; >> + >> +#if defined(CONFIG_ARCH_AT91SAM9G45) ||\ >> + defined(CONFIG_ARCH_AT91SAM9X5) >> +static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl) >> +{ >> + fb_desc->dma_ctrl = ctrl; >> +} >> +#else >> +static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl) { } >> +#endif > Same here, get rid of the ifdefs. I'll remove this. >> [snip] >> + if (!isi->still_capture) { >> + if (pending & (ISI_BIT(V2_VSYNC))) { >> + switch (isi->state) { >> + case STATE_IDLE: >> + isi->state = STATE_CAPTURE_READY; >> + wake_up_interruptible(&isi->capture_wq); >> + break; >> + } >> + } else if (likely(pending & (ISI_BIT(V2_CXFR_DONE)))) { >> + ret = atmel_isi_handle_streaming(isi); >> + } >> + } else { >> + while (pending) { >> + if (pending & (ISI_BIT(V2_C_OVR) | ISI_BIT(V2_FR_OVR))) >> + printk(KERN_ERR "Overrun (status = 0x%x)\n", >> + status); > dev_err(isi->v4l2_dev.dev, "Overrun..."); I will fix it. >> [snip] >> + >> +static int atmel_isi_init(struct atmel_isi *isi) >> +{ >> + /* >> + * The reset will only succeed if we have a >> + * pixel clock from the camera. >> + */ >> + isi_writel(isi, V2_CTRL, ISI_BIT(V2_SRST)); >> + isi_writel(isi, V2_INTDIS, ~0UL); > Don't you need to wait for the reset bit to clear? Other implementations > I have used of the Atmel ISI driver do a wait_for_completition and have > the interrupt handler set a reset_complete flag. You are right. I just remove the reset_complete waiting part in this version. Actually I am thinking whether I need add such code again. >> [snip] >> + if (bytes_per_line < 0) >> + return bytes_per_line; >> + >> + size = bytes_per_line * icd->user_height; >> + >> + if (0 == *nbuffers) > if (*nbuffers == 0) > is the more commonly preferred style I believe. I will fix it for consistency. >> [snip] >> + >> +static int buffer_finish(struct vb2_buffer *vb) >> +{ >> + return 0; >> +} > Does soc-camera support having NULL function callbacks for functions > that are not required? I will remove this function at all. soc-camera can use default callback. >> [snip] >> +static inline void stride_align(u32 *width) >> +{ >> + if (((*width + 7) & ~7) < 4096) >> + *width = (*width + 7) & ~7; >> + else >> + *width = *width & ~7; > This looks like something that may already have a function to do it? Yes. you are right. There is a function ALIGN(*width, 8). And I think I can remove this function since ISI is not sensetive for this width alignment. >> [snip] >> + >> +static int isi_camera_try_fmt(struct soc_camera_device *icd, >> + struct v4l2_format *f) >> +{ >> + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); >> + const struct soc_camera_format_xlate *xlate; >> + struct v4l2_pix_format *pix = &f->fmt.pix; >> + struct v4l2_mbus_framefmt mf; >> + __u32 pixfmt = pix->pixelformat; > u32 inside the kernel, __u32 is for code which is exposed to userspace >(i.e. API headers). I will fixed it. no __u32 anymore. >> [snip] >> +static int test_platform_param(struct atmel_isi *isi, >> + unsigned char buswidth, unsigned long *flags) >> +{ >> + /* >> + * Platform specified synchronization and pixel clock polarities are >> + * only a recommendation and are only used during probing. Atmel ISI >> + * camera interface only works in master mode, i.e., uses HSYNC and >> + * VSYNC signals from the sensor >> + */ >> + *flags = SOCAM_MASTER | >> + SOCAM_HSYNC_ACTIVE_HIGH | >> + SOCAM_HSYNC_ACTIVE_LOW | >> + SOCAM_VSYNC_ACTIVE_HIGH | >> + SOCAM_VSYNC_ACTIVE_LOW | >> + SOCAM_PCLK_SAMPLE_RISING | >> + SOCAM_PCLK_SAMPLE_FALLING | >> + SOCAM_DATA_ACTIVE_HIGH; >> + >> + /* If requested data width is supported by the platform, use it */ >> + switch (buswidth) { >> + case 10: >> + if (!(isi->platform_flags & ISI_DATAWIDTH_10)) >> + return -EINVAL; >> + *flags |= SOCAM_DATAWIDTH_10; >> + break; > If you have specified the platform data width as 10 bits can you not do > 8 bit transfers on it? no, you cannot use 8 bit transfers. But normally we can specify the platform data width to support both 10 and 8. >> [snip] >> +static int isi_camera_querycap(struct soc_camera_host *ici, >> + struct v4l2_capability *cap) >> +{ >> + strcpy(cap->driver, "atmel-isi"); >> + strcpy(cap->card, "Atmel Image Sensor Interface"); >> + cap->version = ATMEL_ISI_VERSION; >> + >> + cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE >> + | V4L2_CAP_READWRITE >> + | V4L2_CAP_STREAMING >> + ); > In other places you have the |'s at the end of the line. Should be > consistent within a file. I will fix it. And I find the same mistake in other place. Thank you. >> + return 0; >> +} >> + >> +static int isi_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) > u32. will be fix. >> [snip] >> + if (dev->platform_data) >> + pdata = (struct isi_platform_data *) dev->platform_data; >> + else { >> + static struct isi_platform_data isi_default_data = { >> + .frate = 0, >> + .has_emb_sync = 0, >> + .emb_crc_sync = 0, >> + .hsync_act_low = 0, >> + .vsync_act_low = 0, >> + .pclk_act_falling = 0, >> + .isi_full_mode = 1, >> + /* to use codec and preview path simultaneously */ >> + .flags = ISI_DATAWIDTH_8 | >> + ISI_DATAWIDTH_10, >> + }; > Move this struct definition outside of this function. OK. I will change that. >> + dev_info(&pdev->dev, >> + "No config available using default values\n"); >> + pdata = &isi_default_data; >> + } >> + >> + isi->pdata = pdata; >> + isi->platform_flags = pdata->flags; >> + if (isi->platform_flags == 0) >> + isi->platform_flags = ISI_DATAWIDTH_8; > We could be mean here an require that people get the flags correct, e.g. > if (!((isi->platform_flags & ISI_DATA_WIDTH_8) || > (isi->platform_flags & ISI_DATA_WIDTH_8))) { > dev_err(&pdev->dev, "No data width specified\n"); > err = -ENOMEM; > goto fail; > } > Which discourages sloppy coding in the board files. now the isi->platform_flags only use for data width, so if it is 0, I will set is as default data width(ISI_DATA_WIDTH_8). I think if we use platform_flags for more option (not only data width), then we need test it with a WIDTH_MASK. >> [snip] Best Regards, Josh Wu -- 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