⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 camif_mx2ads.c

📁 pxa270下的摄像头mtd91111的驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* drivers/media/video/mx2ads/camif_mx2ads.c * * Implementation of Camera Interface for MX2ADS platform. * this driver based on media/video/omap/camif_innovator.c * * Copyright (C) 2004 MontaVista Software, Inc. * * Author: MontaVista Software, Inc. *              source@mvista.com * * 2004 (c) MontaVista Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. */#include <linux/config.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/videodev.h>#include <linux/version.h>#include <linux/interrupt.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/page.h>#include <asm/dma.h>#include <asm/hardware.h>#include <asm/arch/gpio.h>#include <asm/arch/pll.h>#include "prpscale.h"#define MODULE_NAME "camif"#include "common.h"#include "camif.h"static struct camera_interface * this;static canif_chan_stat_t chan_stat[CAMIF_CHANNELS_NUM];static unsigned long camera_clk = 20000000; /* default camera clock*/static spinlock_t camif_lock;static int camera_module_present = 0;static int mem_region_reserved = 0;static int camif_close(int chan);extern const struct image_size mx2ads_image_size[]; /***************************************************************************//*                       EMMA functionality                                *//***************************************************************************/static inline voidemma_disable_interrupts(int chan){        if (chan == 0) {                PRP_INTRCNTL &= ~(PRP2_ICR_CH1 | PRP_INTRCNTL_CH1ERR);        } else {                PRP_INTRCNTL &= ~(PRP2_ICR_CH2 | PRP_INTRCNTL_CH2ERR);        }}static inline voidemma_enable_interrupts(int chan){        if (chan == 0) {                PRP_INTRCNTL |= (PRP2_ICR_CH1 | PRP_INTRCNTL_CH1ERR);        } else {                PRP_INTRCNTL |= (PRP2_ICR_CH2 | PRP_INTRCNTL_CH2ERR);        }}static void emma_prp_isr(int irq, void *client_data, struct pt_regs *regs){	unsigned long flags;        unsigned int isr_reg = PRP_INTRSTATUS;        int i;        canif_chan_stat_t *cstat;        unsigned int chan_masks[CAMIF_CHANNELS_NUM] = {                (PRP_INTRSTAT_CH1BUF2 | PRP_INTRSTAT_CH1BUF1),                (PRP_INTRSTAT_CH2BUF2 | PRP_INTRSTAT_CH2BUF1)        };        unsigned int chan_en = 0;	spin_lock_irqsave(&camif_lock, flags);        PRP_INTRSTATUS = isr_reg;	if (isr_reg & (chan_masks[0] | chan_masks[1])) {                for (i = 0, cstat = &(chan_stat[0]);                                 i< CAMIF_CHANNELS_NUM; i++, cstat++) {                        if (!(isr_reg & chan_masks[i])) {                                continue;                        }                        /* It seems hw bug: Channel bit does not cleared after                         * interrupt recieving */	                PRP_CNTL &= ~(1<<i); /* Clear the channel */                        /* callback to V4L2 layer */                        cstat->capture_callback(cstat->callback_data);                        if (cstat->snapshot_active) {                                cstat->snapshot_active = 0;                        }                        if (cstat->abort) {                                cstat->abort = 0;                                cstat->streaming_active = 0;		                wake_up_interruptible (&cstat->abortqueue);                                emma_disable_interrupts(i);                        }                                        }	} else {                err("eMMa Interrupt error %x\n", PRP_INTRSTATUS);                /* TODO Reset should be done after eMMa error */	}        /* Engage all channels in same time */        for (i = 0, cstat = &(chan_stat[0]);                         i< CAMIF_CHANNELS_NUM; i++, cstat++) {                if (cstat->streaming_active || cstat->snapshot_active) {                        chan_en |= 1 << i;                }        }        PRP_CNTL |= chan_en;	spin_unlock_irqrestore(&camif_lock, flags);}typedef struct _coeff_t {        unsigned int    coeff[2];        unsigned int    cntl;}coeff_t[2][2];static voidprp_set_scaler(int ch, int dir, scale_t *scale){	int	i;	unsigned int	coeff[2];	unsigned int	valid;        volatile coeff_t *prpregs = (void*)&(PRP2_RSZ1_HCOEF1);	for (coeff[0] = coeff[1] = valid = 0, i = 19; i >= 0; i--)	{		int	j;		j = i > 9 ? 1 : 0;		coeff[j] = (coeff[j] << BC_COEF) | 			(scale->tbl[i] & (SZ_COEF - 1));		if (i == 5 || i == 15)		{			coeff[j] <<= 1;		}		valid = (valid << 1) | (scale->tbl[i] >> BC_COEF);	}	valid |= (scale->len << 24) | ((2 - scale->algo) << 31);	for (i = 0; i < 2; i++)	{		(*prpregs)[ch][dir].coeff[i] = coeff[i];	}	(*prpregs)[ch][dir].cntl = valid;}static intemma_prp_scale(unsigned int channel, int camwidth, int camheight,                 unsigned short *prpwidth, unsigned short *prpheight){        int ret;	scale_t		scale[2];        unsigned short res_width, res_height;        	memset(scale, 0, sizeof(scale));	scale[0].algo = 0;	scale[1].algo = 0;	ret = prp_scale(&(scale[0]), 0, 0,		camwidth,                 prpwidth,                 &res_width);	if (ret)	{                err("Width rescaling error\n");		return ret;	}        *prpwidth = res_width;	ret = prp_scale(&(scale[1]), 0 , 1, 		camheight,                 prpheight,                 &res_height);	if (ret)	{                err("Height rescaling error\n");		return ret;	}        *prpheight = res_height;        prp_set_scaler(channel, 0, &(scale[0]));        prp_set_scaler(channel, 1, &(scale[1]));        return 0;}#define CSC_RGB_TO_YUV          (0)#define CSC_YUV_TO_RGB          (1)#define EQUATION_A1             (0)#define EQUATION_A0             (1)#define EQUATION_B1             (2)#define EQUATION_B0             (3)/* Lasr coeficient define Video range */static const unsigned shortcsc_convmatrix[2][4][10] = {    {        /* RGB to YUV conversion */        {0x4D, 0x4B, 0x3A, 0x57, 0x55, 0x40, 0x40, 0x6B, 0x29, 0x01 },/* A1 */        {0x42, 0x41, 0x32, 0x4C, 0x4A, 0x38, 0x38, 0x5E, 0x24, 0x00 },/* A0 */        {0x36, 0x5C, 0x25, 0x3B, 0x63, 0x40, 0x40, 0x74, 0x18, 0x01 },/* B1 */        {0x2F, 0x4F, 0x20, 0x34, 0x57, 0x38, 0x38, 0x66, 0x15, 0x00 },/* B0 */    },    {         /* YUV to RGB */         {0x80, 0xb4, 0x2c, 0x5b, 0x0e4, 0x00, 0x00, 0x00, 0x00, 0x01},/* A1 */         {0x95, 0xcc, 0x32, 0x68, 0x104, 0x00, 0x00, 0x00, 0x00, 0x00},/* A0 */         {0x80, 0xca, 0x18, 0x3c, 0x0ec, 0x00, 0x00, 0x00, 0x00, 0x01},/* B1 */         {0x95, 0xe5, 0x1b, 0x44, 0x1e0, 0x00, 0x00, 0x00, 0x00, 0x00},/* B0 */    }};/* Return pointer to appropriative coeficient set *//* FIXME: Currently only YUV with full range (0-255) is used (A1 equation ). To * used YCrCb special color type or ioctl should be implemented */const unsigned short * get_csc_coefs(void){        enum pixel_format camfmt = this->camera->pixfmt;        int conversion = 0;        int equation = EQUATION_A1;        switch (camfmt) {                case YUV:                        conversion = CSC_YUV_TO_RGB;                        break;                case RGB565:                        conversion = CSC_RGB_TO_YUV;                        break;                default:                        return NULL;        }        return csc_convmatrix[conversion][equation];}static intemma_set_videoformat(void){        unsigned short const *csc_coefs;        csc_coefs = get_csc_coefs();        if (!csc_coefs) {                return -EINVAL;        }        PRP2_CSC_COEF0 = (csc_coefs[0] << 21) |                (csc_coefs[1] << 11) | csc_coefs[2];        PRP2_CSC_COEF1 = (csc_coefs[3] << 21) |                (csc_coefs[4] << 11) | csc_coefs[5];        PRP2_CSC_COEF2 = (csc_coefs[6] << 21) |                (csc_coefs[7] << 11) | csc_coefs[8] |                (csc_coefs[9] << 31);        return 0;}static intemma_set_format(unsigned int chan, struct v4l2_pix_format *fmt){        unsigned int camwidth =                 mx2ads_image_size[this->camera->imgfmt].width;        unsigned int camheight=                mx2ads_image_size[this->camera->imgfmt].height;        unsigned short prpwidth = fmt->width;        unsigned short prpheight = fmt->height;                if (emma_prp_scale(chan, camwidth, camheight, &prpwidth, &prpheight)) {                return -EINVAL;        }        if (chan == 0) {                PRP_CH1_OUT_IMAGE_SIZE          =                         ((prpwidth    & 0x7FF)  << 16)        |                        ((prpheight   & 0x7FF))               ;                PRP_CH1_DEST_FRAME_CNTL = prpwidth * fmt->depth/8;        } else {                PRP_CH2_OUT_IMAGE_SIZE =                         ((prpwidth    & 0x7FF)  << 16)        |                        ((prpheight   & 0x7FF))               ;        }        chan_stat[chan].width = prpwidth;        chan_stat[chan].height = prpheight;        chan_stat[chan].depth = fmt->depth;        /* set videoformat */        if (emma_set_videoformat()) {                err("eMMa does not support current cumera format\n");                return -EINVAL;        }        return 0;}/************************************************************************** * MX21 CSI module specific functions **************************************************************************//* Dma channel for data tranfer between CSI and memory buffer *//* Pointer to the memory area for image capturing via DMA and size of memory area */static int camif_set_format(unsigned int chan, struct v4l2_pix_format* fmt){        unsigned int prppixfmtreg;        unsigned int prp_cntl = 0, prp_cntl_mask = 0xFFFFFFFF, reg;                int ret;        	unsigned long flags;        canif_chan_stat_t *cstat = &(chan_stat[chan]);                if (cstat->snapshot_active || cstat->streaming_active) {                return -EINVAL;        }        	spin_lock_irqsave(&camif_lock, flags);        if (chan_stat[1-chan].opened) {                                unsigned int camwidth =                         mx2ads_image_size[this->camera->imgfmt].width;                unsigned int camheight=                        mx2ads_image_size[this->camera->imgfmt].height;                if ((fmt->width > camwidth) || (fmt->height > camheight)) {                        err("Dynamic change resolution currently is not "                             "supported\n Please open channel with greatest "                             "resolution first\n");                        spin_unlock_irqrestore(&camif_lock, flags);                        return -EINVAL;                }        } else { /* No active channel */                if(this->camera) {                        struct v4l2_pix_format camfmt = *fmt;                        camfmt.pixelformat = V4L2_PIX_FMT_RGB565;                        /* Trying to change format on camera */                        /*FIXME: It seems the prp cannot accept image in 176x144                         * format so trying to workarond this: Setup 320x240                         * resolution and use prp scaling to get requested                         * resolution */                        unsigned int res = fmt->width * fmt->height;                        if ((res > (160 * 120)) && (res <= (176 * 144))) {                                camfmt.width = 320;                                camfmt.height = 240;                        }                        if (this->camera->set_format(&camfmt)) {                                /* FIXME: In this case we can try to set pixel                                 * format of same kind, but which is uspported                                 * by camera (e.g. if RGB 555 is not supported                                 * but RGB565 is supported try to change to                                 * RGB565) which is supported. After the eMMa                                 * hardware will be initialized, the conversion                                 * will be done by PRP module */                                 /* Currently the feature described above does                                  * not supported */                                err("Unable to set request format\n");                        	spin_unlock_irqrestore(&camif_lock, flags);                                return -EINVAL;                        }                                                prp_cntl_mask &= ~(PRP2_CNTL_IN_RGB32);                        prppixfmtreg = 0x2CA00565;                        PRP_SOURCE_FRAME_FORMAT_CNTL    = prppixfmtreg;                        prp_cntl |= PRP2_CNTL_IN_RGB;                                PRP_SOURCE_FRAME_SIZE =                              ((camfmt.width & 0x7FF) << 16) | 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -