云终端linux系统,让同方安全的云终端运行于Linux系统之上(二)

4、显示驱动

与云终端显示相关的硬件包括多层控制器(MLC)及显示控制器(DPC)。MLC对应的修改的程序是mlc.c、mlc.h、main.c,

DPC对应修改的程序为dpc_config.h、dpc_ioctl.h及main.c。修改主要涉及MLC顶层的初始设置、显示LOGO设置、及系统默认显示分辨率的设置、及与Pollux硬件相关的系统设置。对于DPC部分的修改主要为系统默认显示分辨率的设置及与其相关的控制信号HSYNC_SWIDTH、HSYNC_FRONT_PORCH、HSYNC_BACK_PORCH、HSYNC_ACTIVEHIGH、VSYNC_SWIDTH、VSYNC_FRONT_PORCH、DISPLAY_VID_PRI_VCLK_SOURCE、DPC_DESIRED_CLOCK_HZ等设置。

5、 I2C系统总线

参考系统使用了一条I2C总线,而Pollux系统使用使用了两条系统总线,一条连接到加密芯片、另一条连接到声音的i2S。所以修改驱动为识别及支持两条系统总线。以下为驱动程序。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define

I2C_CHANNEL CONFIG_I2C_LF1000_CHANNEL

#define LF1000_I2C_TIMEOUT 10

#define LF1000_I2C_RATE_HZ 100000

#ifdef CPU_LF1000

#define I2C_SCL0_PORT GPIO_PORT_A

#define I2C_SCL0_PIN 26

#define I2C_SCL0_FN GPIO_ALT1

#define I2C_SDA0_PORT GPIO_PORT_A

#define I2C_SDA0_PIN 27

#define I2C_SDA0_FN GPIO_ALT1

#define I2C_SCL1_PORT GPIO_PORT_A

#define I2C_SCL1_PIN 28

#define I2C_SCL1_FN GPIO_ALT1

#define I2C_SDA1_PORT GPIO_PORT_A

#define I2C_SDA1_PIN 29

#define I2C_SDA1_FN GPIO_ALT1

#endif

enum lf1000_i2c_state {

I2C_SEND_ADDR,

I2C_SEND_DATA,

I2C_SEND_DONE,

};

struct lf1000_i2c {

void __iomem *base;

int irq;

int div;

wait_queue_head_t wait;

int ready;

wait_queue_head_t bus_access;

int busy;

};

static struct lf1000_i2c dev[2] = {

{

.base = NULL,

.irq = -1,

.ready = 0,

.div = 16,

.busy = 0

},

{

.base = NULL,

.irq = -1,

.ready = 0,

.div = 16,

.busy = 0

}

};

static irqreturn_t lf1000_i2c_irq(int irq, void *dev_id)

{

struct platform_device *pdev = dev_id;

int ch = pdev->id;

u32 tmp = ioread32(dev[ch].base+IRQ_PEND);

if(!(tmp &

(1<

return IRQ_NONE;

tmp |=

(1<

iowrite32(tmp, dev[ch].base+IRQ_PEND);

dev[ch].ready = 1;

wake_up_interruptible(&dev[ch].wait);

return IRQ_HANDLED;

}

static int lf1000_i2c_wait(struct i2c_adapter *adap)

{

struct platform_device *pdev =

to_platform_device(adap->dev.parent);

int ch =

pdev->id;

int ret =

wait_event_interruptible_timeout(dev[ch].wait,

(dev[ch].ready),

LF1000_I2C_TIMEOUT);

if(unlikely(ret < 0))

printk(KERN_INFO "i2c:

interrupted\n");

else if(unlikely(!(dev[ch].ready)))

return -ETIMEDOUT;

dev[ch].ready = 0;

return 0;

}

static int i2c_bus_available(struct i2c_adapter *adap)

{

unsigned long flags;

int ret;

struct platform_device *pdev =

to_platform_device(adap->dev.parent);

int ch =

pdev->id;

spin_lock_irqsave(&dev[ch].bus_access,

flags);

ret = !(dev[ch].busy);

spin_unlock_irqrestore(&dev[ch].bus_access,

flags);

return ret;

}

static void start_stop_condition(struct i2c_adapter *adap)

{

struct platform_device *pdev =

to_platform_device(adap->dev.parent);

int ch =

pdev->id;

u32 tmp = ioread32(dev[ch].base+IRQ_PEND);

tmp |=

(1<

iowrite32(tmp, dev[ch].base+IRQ_PEND);

}

static void lf1000_i2c_clock(char en, struct i2c_adapter

*adap)

{

struct platform_device *pdev =

to_platform_device(adap->dev.parent);

int ch =

pdev->id;

u32 tmp = ioread32(dev[ch].base+I2C_CLKENB);

en ? BIT_SET(tmp, 3) :BIT_CLR(tmp, 3);

iowrite32(tmp, dev[ch].base+I2C_CLKENB);

}

static void lf1000_i2c_hwinit(struct i2c_adapter *adap)

{

struct platform_device *pdev =

to_platform_device(adap->dev.parent);

int ch =

pdev->id;

iowrite32(0, dev[ch].base+ICCR);

#ifdef CPU_MF2530F

iowrite32(0, dev.base+BURST_CTRL);

#endif

iowrite32((1<

dev[ch].base+ICCR);

iowrite32((1<

dev[ch].base+QCNT_MAX);

iowrite32(0x1010, dev[ch].base+ICSR);

start_stop_condition(adap); }

static int xfer_write(struct i2c_adapter *adap, unsigned char *buf,

int length)

{

u32 tmp;

int ret;

enum lf1000_i2c_state state =

I2C_SEND_ADDR;

struct platform_device *pdev =

to_platform_device(adap->dev.parent);

int ch =

pdev->id;

tmp = (ioread32(dev[ch].base+ICSR)

& 0x10F0);

tmp |=

((1<

(1<

iowrite32(tmp, dev[ch].base+ICSR);

start_stop_condition(adap);

while(1) {

switch(state) {

case

I2C_SEND_ADDR:

ret =

lf1000_i2c_wait(adap);

if(ret !=

0)

goto

done_write;

tmp =

ioread32(dev[ch].base+ICSR);

if(tmp

& (1<

{

printk(KERN_INFO

"i2c: no ACK in xfer_write\n");

ret

= -EFAULT;

goto

done_write;

}

state =

I2C_SEND_DATA;

break;

case

I2C_SEND_DATA:

iowrite32(*buf++,

dev[ch].base+IDSR);

start_stop_condition(adap);

ret =

lf1000_i2c_wait(adap);

if(ret !=

0)

goto

done_write;

if(--length

<= 0)

state

= I2C_SEND_DONE;

break;

case

I2C_SEND_DONE:

ret =

0;

goto

done_write;

}

}

done_write:

tmp = (ioread32(dev[ch].base+ICSR)

& 0x1F0F);

tmp |=

((1<

iowrite32(tmp, dev[ch].base+ICSR);

start_stop_condition(adap);

iowrite32(0, dev[ch].base+ICSR);

return 0;

}

static int xfer_read(struct i2c_adapter *adap, unsigned char *buf,

int length)

{

u32 tmp;

int ret;

enum lf1000_i2c_state state =

I2C_SEND_ADDR;

struct platform_device *pdev =

to_platform_device(adap->dev.parent);

int ch =

pdev->id;

tmp = (ioread32(dev[ch].base+ICSR)

& 0x1F0F);

tmp |=

((1<

(1<

iowrite32(tmp, dev[ch].base+ICSR);

start_stop_condition(adap);

while(1) {

switch(state) {

case

I2C_SEND_ADDR:

ret =

lf1000_i2c_wait(adap);

if(ret !=

0)

goto

done_read;

tmp =

ioread32(dev[ch].base+ICSR);

if(tmp

& (1<

{

printk(KERN_INFO

"i2c: no ACK in xfer_read\n");

ret

= -EFAULT;

goto

done_read;

}

state =

I2C_SEND_DATA;

break;

case

I2C_SEND_DATA:

*buf++ =

ioread32(dev[ch].base+IDSR);

start_stop_condition(adap);

ret =

lf1000_i2c_wait(adap);

if(ret !=

0)

goto

done_read;

if(--length

<= 0)

state

= I2C_SEND_DONE;

break;

case

I2C_SEND_DONE:

ret =

0;

goto

done_read;

}

}

done_read:

tmp = ioread32(dev[ch].base+ICSR);

tmp &= ~(0x1F0F);

tmp |=

((1<

iowrite32(tmp, dev[ch].base+ICSR);

start_stop_condition(adap);

iowrite32(0, dev[ch].base+ICSR);

return ret;

}

static int lf1000_xfer(struct i2c_adapter *adap, struct i2c_msg

*pmsg, int num)

{

int i, ret;

unsigned long flags;

struct platform_device *pdev =

to_platform_device(adap->dev.parent);

int ch =

pdev->id;

spin_lock_irqsave(&dev[ch].bus_access,

flags);

while(dev[ch].busy) {

spin_unlock_irqrestore(&dev[ch].bus_access,

flags);

if(wait_event_interruptible(dev[ch].bus_access,

i2c_bus_available(adap))) {

dev[ch].busy

= 0;

spin_unlock_irqrestore(&dev[ch].bus_access,

flags);

return

-ERESTARTSYS;

}

spin_lock_irqsave(&dev[ch].bus_access,

flags);

}

dev[ch].busy = 1;

spin_unlock_irqrestore(&dev[ch].bus_access,

flags);

lf1000_i2c_clock(1,adap);

for(i = 0; i < num; i++)

{

lf1000_i2c_hwinit(adap);

iowrite32(pmsg->addr

| ((pmsg->flags & I2C_M_RD) ? 1 :

0),

dev[ch].base+IDSR);

if(pmsg->len

&& pmsg->buf)

{

if(pmsg->flags

& I2C_M_RD)

ret

= xfer_read(adap, pmsg->buf,

pmsg->len);

else

ret

= xfer_write(adap, pmsg->buf,

pmsg->len);

if(ret !=

0)

goto

xfer_done;

}

pmsg++;

}

ret = i;

xfer_done:

lf1000_i2c_clock(0,adap);

spin_lock_irqsave(&dev[ch].bus_access,

flags);

dev[ch].busy = 0;

spin_unlock_irqrestore(&dev[ch].bus_access,

flags);

return ret;

}

static u32 lf1000_func(struct i2c_adapter *adapter)

{

return

I2C_FUNC_I2C;

}

static struct i2c_algorithm lf1000_algorithm = {

.master_xfer = lf1000_xfer,

.functionality = lf1000_func,

};

static int lf1000_i2c_probe(struct platform_device *pdev)

{

struct resource *res;

struct i2c_adapter *adapter;

int ret = 0;

unsigned int pclk_hz;

int ch =

pdev->id;

res = platform_get_resource(pdev,

IORESOURCE_MEM, I2C_CHANNEL);

if(!res) {

printk(KERN_ERR "i2c: failed to

get resource\n");

return -ENXIO;

}

if(!request_mem_region(res->start,

(res->end - res->start) + 1,

"lf1000_i2c")) {

printk(KERN_ERR "i2c: failed to

request_mem_region\n");

return -EBUSY;

}

dev[ch].base =

ioremap(res->start, (res->end -

res->start) + 1);

if(dev[ch].base == NULL) {

printk(KERN_ERR "i2c: failed to

ioremap\n");

ret = -ENOMEM;

goto fail_remap;

}

adapter = kzalloc(sizeof(struct i2c_adapter),

GFP_KERNEL);

if(adapter == NULL) {

printk(KERN_ERR "i2c: failed to

allocate interface\n");

ret = -ENOMEM;

goto fail_adapter;

}

sprintf(adapter->name,

"LF1000");

adapter->algo =

&lf1000_algorithm;

adapter->class =

I2C_CLASS_HWMON;

adapter->dev.parent =

&pdev->dev;

platform_set_drvdata(pdev, adapter);

dev[ch].irq = platform_get_irq(pdev,

I2C_CHANNEL);

if(dev[ch].irq < 0) {

printk(KERN_ERR "i2c: failed to

get an IRQ\n");

ret = dev[ch].irq;

goto fail_irq;

}

ret = request_irq(dev[ch].irq,

lf1000_i2c_irq,

SA_INTERRUPT|SA_SAMPLE_RANDOM,

"i2c", pdev);

if(ret) {

printk(KERN_ERR "i2c:

requesting IRQ failed\n" );

goto fail_irq;

}

init_waitqueue_head(&dev[ch].wait);

init_waitqueue_head(&dev[ch].bus_access);

pclk_hz =

get_pll_freq(PCLK_PLL)/BCLK_DIV/2;

dev[ch].div = lf1000_CalcDivider(pclk_hz/256,

LF1000_I2C_RATE_HZ);

if(dev[ch].div < 0) {

printk(KERN_ALERT "i2c: failed

to get divider, using 16\n");

dev[ch].div = 16;

}

else if(dev[ch].div > 16) {

printk(KERN_ALERT "i2c: divider

too high, using 16\n");

dev[ch].div = 16;

}

if (pclk_hz/256/dev[ch].div <

LF1000_I2C_RATE_HZ)

dev[ch].div--;

else if (pclk_hz/256/dev[ch].div >

1000*1000 )

printk("i2c: 2IC bus frequency too high\n");

printk("I2C bus %d frequency set to %d KHz,

address at %x IRQ %d\n", ch,

pclk_hz/256/dev[ch].div/1000, res->start,

dev[ch].irq);

if(ch == 0 ) {

#ifdef I2C_SCL0_PORT

gpio_configure_pin(I2C_SCL0_PORT, I2C_SCL0_PIN,

I2C_SCL0_FN, 1, 0, 0);

#endif

#ifdef I2C_SDA0_PORT

gpio_configure_pin(I2C_SDA0_PORT, I2C_SDA0_PIN,

I2C_SDA0_FN, 1, 0, 0);

#endif

}

else if (ch == 1) {

#ifdef I2C_SCL1_PORT

gpio_configure_pin(I2C_SCL1_PORT, I2C_SCL1_PIN,

I2C_SCL1_FN, 1, 0, 0);

#endif

#ifdef I2C_SDA1_PORT

gpio_configure_pin(I2C_SDA1_PORT, I2C_SDA1_PIN,

I2C_SDA1_FN, 1, 0, 0);

#endif

}

lf1000_i2c_hwinit(adapter);

lf1000_i2c_clock(1,adapter);

ret = i2c_add_adapter(adapter);

if(ret != 0) {

printk(KERN_ERR "i2c: failed to

add adapter\n");

goto fail_register;

}

printk("I2C adapter %s registered\n",

adapter->dev.bus_id);

return 0;

fail_register:

lf1000_i2c_clock(0,adapter);

platform_set_drvdata(pdev, NULL);

kfree(adapter);

fail_irq:

free_irq(dev[ch].irq, NULL);

dev[ch].irq = -1;

fail_adapter:

iounmap(dev[ch].base);

fail_remap:

release_mem_region(res->start,

(res->end - res->start) + 1);

return ret;

}

static int lf1000_i2c_remove(struct platform_device *pdev)

{

struct i2c_adapter *adapter =

platform_get_drvdata(pdev);

struct resource *res;

int ret;

int ch = pdev->id;

if(adapter != NULL) {

lf1000_i2c_clock(0,adapter);

ret =

i2c_del_adapter(adapter);

platform_set_drvdata(pdev,

NULL);

res =

platform_get_resource(pdev, IORESOURCE_MEM, 0);

iounmap(dev[ch].base);

release_mem_region(res->start,

(res->end - res->start) + 1);

return ret;

}

return 0;

}

#ifdef CONFIG_PM

static int lf1000_i2c_suspend(struct platform_device *pdev,

pm_message_t mesg)

{

struct i2c_adapter *adap =

i2c_get_adapter(pdev->id);

lf1000_i2c_clock(0, adap);

return 0;

}

static int lf1000_i2c_resume(struct platform_device *pdev)

{

struct i2c_adapter *adap =

i2c_get_adapter(pdev->id);

lf1000_i2c_clock(1, adap);

return 0;

}

#else

#define lf1000_i2c_suspend NULL

#define lf1000_i2c_resume NULL

#endif

static struct platform_driver lf1000_i2c_driver = {

.probe = lf1000_i2c_probe,

.remove = lf1000_i2c_remove,

.suspend = lf1000_i2c_suspend,

.resume = lf1000_i2c_resume,

.driver = {

.name = "lf1000-i2c",

.owner =

THIS_MODULE,

},

};

static int __init lf1000_i2c_init(void)

{

return

platform_driver_register(&lf1000_i2c_driver);

}

static void __exit lf1000_i2c_exit(void)

{

return

platform_driver_unregister(&lf1000_i2c_driver);

}

module_init(lf1000_i2c_init);

module_exit(lf1000_i2c_exit);

MODULE_AUTHOR("Andrey Yurovsky");

MODULE_DESCRIPTION("I2C driver for LF1000");

MODULE_LICENSE("GPL");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值