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

📄 lcdc.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
字号:
/* * linux/arch/arm/mach-omap/lcdc.c * * OMAP LCD controller * * Copyright (C) 2004 Nokia Corporation * Author: Imre Deak <imre.deak@nokia.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */					#include <linux/kernel.h>#include <linux/device.h>#include <linux/interrupt.h>#include <linux/spinlock.h>#include <linux/err.h>#include <asm/hardware.h>#include <asm/mach-types.h>#include <asm/hardware/clock.h>#include "lcdc.h"struct lcd_controller {	int			initialized;	void			*owner;	spinlock_t		spinlock;	int			active;	struct completion	done_comp;	u32			irq_mask;	u32			stat_mask;	lcdc_irq_handler_t	irq_handler;	unsigned long		handler_data;	struct clk *		lcd_ck;};static struct lcd_controller lcdc;int omap_lcdc_request(void *devid, lcdc_irq_handler_t handler,		      unsigned long handler_data){	BUG_ON(devid == (void *)-1);	if (!lcdc.initialized) {		printk(KERN_ERR "lcdc: not initialized\n");		return -1;	}	spin_lock_irq(&lcdc.spinlock);	if (lcdc.owner != (void *)-1) {		printk(KERN_ERR "lcdc: already reserved\n");		spin_unlock_irq(&lcdc.spinlock);		return -1;	}	lcdc.owner = devid;	spin_unlock_irq(&lcdc.spinlock);	lcdc.active = 0;	lcdc.irq_mask = 0;	lcdc.stat_mask = 0;	lcdc.irq_handler = handler;	lcdc.handler_data = handler_data;	return 0;}void omap_lcdc_release(void *devid){	BUG_ON(devid != lcdc.owner);	lcdc.owner = (void *)-1;}void omap_lcdc_set_config(int tft, int signal_levels){	u32 l;	l = omap_readl(OMAP_LCDC_CONTROL);	l &= ~OMAP_LCDC_CTRL_LCD_TFT;	l |= tft ? OMAP_LCDC_CTRL_LCD_TFT : 0;	omap_writel(l, OMAP_LCDC_CONTROL);	l = omap_readl(OMAP_LCDC_TIMING2);	l &= ~(((1 << 6) - 1) << 20);	l |= signal_levels << 20;	omap_writel(l, OMAP_LCDC_TIMING2);}void omap_lcdc_set_video_mode(struct lcdc_video_mode *mode){	u32 l;	l = mode->x_res - 1;	l |= (mode->hsw - 1) << 10;	l |= (mode->hfp - 1) << 16;	l |= (mode->hbp - 1) << 24;	omap_writel(l, OMAP_LCDC_TIMING0);	l = mode->y_res - 1;	l |= (mode->vsw - 1) << 10;	l |= mode->vfp << 16;	l |= mode->vbp << 24;	omap_writel(l, OMAP_LCDC_TIMING1);	l = omap_readl(OMAP_LCDC_TIMING2);	l &= ~0xff;	l |= mode->pcd;	l |= mode->acb << 8;	omap_writel(l, OMAP_LCDC_TIMING2);}void omap_lcdc_set_load_mode(enum lcdc_load_mode load_mode){	u32 l;	l = omap_readl(OMAP_LCDC_CONTROL);	l &= ~(3 << 20);	switch (load_mode) {	case OMAP_LCDC_LOAD_PALETTE:		l |= 1 << 20;		break;	case OMAP_LCDC_LOAD_FRAME:		l |= 2 << 20;		break;	case OMAP_LCDC_LOAD_PALETTE_AND_FRAME:		break;	default:		BUG();	}	omap_writel(l, OMAP_LCDC_CONTROL);}int omap_lcdc_get_palette_size(struct lcdc_video_mode *mode){	switch (mode->bpp) {	case 1:	case 2:	case 4:	case 8:		return 256;	case 12:	case 16:		return 32;	default:		BUG();	}	return 0;}static void __enable_irqs(int irq_mask, int enable){	int stat_mask = 0;	if (irq_mask & OMAP_LCDC_IRQ_LOADED_PALETTE)		stat_mask |=  OMAP_LCDC_STAT_LOADED_PALETTE;	if (irq_mask & OMAP_LCDC_IRQ_VSYNC)		stat_mask |= OMAP_LCDC_STAT_VSYNC;	if (irq_mask & OMAP_LCDC_IRQ_DONE)		stat_mask |= OMAP_LCDC_STAT_DONE;	if (irq_mask & (OMAP_LCDC_IRQ_LINE | OMAP_LCDC_IRQ_LINE_NIRQ))		stat_mask |= OMAP_LCDC_STAT_LINE_INT;	if (enable) {		lcdc.irq_mask |= irq_mask;		lcdc.stat_mask |= stat_mask;	} else {		lcdc.irq_mask &= ~irq_mask;		lcdc.stat_mask &= ~stat_mask;	}}void omap_lcdc_enable_irqs(int mask){	__enable_irqs(mask, 1);}void omap_lcdc_disable_irqs(int mask){	__enable_irqs(mask, 0);}void omap_lcdc_set_line_irq(int line){	u32 l;	BUG_ON(line >= 1024);	l = omap_readl(OMAP_LCDC_LINE_INT);	l &= ~1023;	l |= line;	omap_writel(l, OMAP_LCDC_LINE_INT);}void omap_lcdc_init_palette(struct lcdc_video_mode *mode,			    void *palette, int size){	memset(palette, 0, size);	switch (mode->bpp) {	case 1:		/* 0 is already set */		break;	case 2:		*(u32 *)palette = 0x1000;		break;	case 4:		*(u32 *)palette = 0x2000;		break;	case 8:		*(u32 *)palette = 0x3000;		break;	case 12:	case 16:		*(u32 *)palette = 0x4000;		break;	default:		BUG();	}}void omap_lcdc_enable(void){	u32 l;	BUG_ON(lcdc.irq_mask && !lcdc.irq_handler);	lcdc.active = 1;	l = omap_readl(OMAP_LCDC_CONTROL);	l |= OMAP_LCDC_CTRL_LCD_EN;	l &= ~OMAP_LCDC_IRQ_MASK;	l |= lcdc.irq_mask | OMAP_LCDC_IRQ_DONE;	/* enabled IRQs */	omap_writel(l, OMAP_LCDC_CONTROL);}void omap_lcdc_disable_async(void){	u32 l;	u32 mask;	lcdc.active = 0;	init_completion(&lcdc.done_comp);	l = omap_readl(OMAP_LCDC_CONTROL);	mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK;	/* Preserve the DONE mask, since we still want to get the	 * final DONE irq. It will be sdisabled in the IRQ handler.	 */	mask &= ~OMAP_LCDC_IRQ_DONE;	l &= ~mask;	omap_writel(l, OMAP_LCDC_CONTROL);}static void omap_lcdc_done_timeout(unsigned long data){	printk(KERN_ERR "lcdc: timeout waiting for DONE\n");	complete(&lcdc.done_comp);}void omap_lcdc_disable(void){	struct timer_list timeout;	omap_lcdc_disable_async();	init_timer(&timeout);	timeout.function = omap_lcdc_done_timeout;	timeout.expires = jiffies + HZ / 10;	/* 100 ms */	add_timer(&timeout);	wait_for_completion(&lcdc.done_comp);	del_timer(&timeout);}static void omap_lcdc_reset(u32 status){	static unsigned long reset_count = 0;	static unsigned long last_jiffies = 0;	omap_lcdc_disable_async();	reset_count++;	if (reset_count == 1 ||	    time_after(jiffies, last_jiffies + HZ)) {		printk(KERN_ERR "lcdc: resetting "				 "(status %#010x,reset count %lu)\n",				  status, reset_count);		last_jiffies = jiffies;	}	if (reset_count < 100) {		omap_lcdc_enable();	} else {		reset_count = 0;		printk(KERN_ERR "lcdc: too many reset attempts, "				"giving up.\n");	}}static irqreturn_t omap_lcdc_irq_handler(int irq, void *dev_id,					 struct pt_regs *fp){	int reset = 0;	u32 status;	status = omap_readl(OMAP_LCDC_STATUS);	if (status & OMAP_LCDC_STAT_FUF)	/* FIFO underflow */		reset = 1;	if (status & OMAP_LCDC_STAT_SYNC_LOST)		reset = 1;	if (status & OMAP_LCDC_STAT_DONE) {		u32 l;		/* Disable IRQ_DONE. The status bit will be cleared		 * only when the controller is reenabled and we don't		 * want to get more interrupts.		 */		l = omap_readl(OMAP_LCDC_CONTROL);		l &= ~OMAP_LCDC_IRQ_DONE;		omap_writel(l, OMAP_LCDC_CONTROL);		complete(&lcdc.done_comp);	}	if (reset)		omap_lcdc_reset(status);	else if (status & lcdc.stat_mask)		lcdc.irq_handler(status, lcdc.handler_data);	/* Clear these interrupt status bits.	 * Sync_lost, FUF bits were cleared by disabling the LCD controller	 * LOADED_PALETTE can be cleared this way only in palette only	 * load mode. In other load modes it's cleared by disabling the	 * controller.	 */	status &= ~(OMAP_LCDC_STAT_VSYNC |		    OMAP_LCDC_STAT_LOADED_PALETTE |		    OMAP_LCDC_STAT_ABC |		    OMAP_LCDC_STAT_LINE_INT);	omap_writel(status, OMAP_LCDC_STATUS);	return IRQ_HANDLED;}int omap_lcdc_init(void){	u32 l;	int rate;	int r;	struct clk *tc_ck;	l = 0;	omap_writel(l, OMAP_LCDC_CONTROL);	/* FIXME:	 * According to errata some platforms have a clock rate limitiation	 */	lcdc.lcd_ck = clk_get(0, "lcd_ck");	if (IS_ERR(lcdc.lcd_ck)) {		printk(KERN_ERR "lcdc: unable to access LCD clock\n");		return PTR_ERR(lcdc.lcd_ck);	}	tc_ck = clk_get(0, "tc_ck");	if (IS_ERR(tc_ck)) {		printk(KERN_ERR "lcdc: unable to access TC clock\n");		clk_put(lcdc.lcd_ck);		return PTR_ERR(tc_ck);	}	rate = clk_get_rate(tc_ck);	clk_put(tc_ck);	if (machine_is_omap_innovator() || machine_is_omap_h3() ||            machine_is_omap_osk())		rate /= 3;	if (clk_set_rate(lcdc.lcd_ck, rate) < 0)		printk(KERN_WARNING "lcdc: failed to adjust LCD rate\n");	clk_use(lcdc.lcd_ck);	if ((r = request_irq(OMAP_LCDC_IRQ, omap_lcdc_irq_handler,			0, "omap-lcdc", 0)) < 0) {		printk(KERN_ERR "lcdc: unable to get IRQ\n");		return r;	}	spin_lock_init(&lcdc.spinlock);	lcdc.owner = (void *)-1;	lcdc.initialized = 1;	printk(KERN_INFO "OMAP LCD controller initialized.\n");	return 0;}void omap_lcdc_cleanup(void){	clk_unuse(lcdc.lcd_ck);	clk_put(lcdc.lcd_ck);	free_irq(OMAP_LCDC_IRQ, 0);}EXPORT_SYMBOL(omap_lcdc_request);EXPORT_SYMBOL(omap_lcdc_release);EXPORT_SYMBOL(omap_lcdc_set_config);EXPORT_SYMBOL(omap_lcdc_set_video_mode);EXPORT_SYMBOL(omap_lcdc_set_load_mode);EXPORT_SYMBOL(omap_lcdc_set_line_irq);EXPORT_SYMBOL(omap_lcdc_init_palette);EXPORT_SYMBOL(omap_lcdc_enable_irqs);EXPORT_SYMBOL(omap_lcdc_disable_irqs);EXPORT_SYMBOL(omap_lcdc_get_palette_size);EXPORT_SYMBOL(omap_lcdc_enable);EXPORT_SYMBOL(omap_lcdc_disable);EXPORT_SYMBOL(omap_lcdc_disable_async);MODULE_DESCRIPTION("TI OMAP LCDC controller");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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