rw9uao
Группа: Клиенты
Пункты: 6973
Регистрация: 26.03.2009
Саш, я не туда смотрю? что-то дешевле $80-$100 не вижу. ткни ссылку. и заодно поболее разрешением.
sasa
Регистрация: 20.05.2009
Lavin (Guest)
Если я правильно понял для lp020
spi->max_speed_hz = 12 * 1000 * 1000;
spi->bits_per_word = 16;//8
spi->mode = SPI_MODE_0;
и переписать инициализацию и команда\данные на GPIO повесить.
Драйвер можно потом будет с карточки подгрузить из консоли или его обязательно с ядром собирать?
sasa
Регистрация: 20.05.2009
Я в исходниках ядра все делаю, модуль компилится после изменений за считанные секунды, а spi привязан в файле board-... который в ядре, так что не вижу смысла выносить сборку из исходников ядра. Потом если модуль глючит - не думаю что его можно безболезненно выгрузить в режиме force а потом снова погрузить измененный. На деле если прошла probe и видно что lcd откликается на управление - то почти все сделано :)
sasa
Регистрация: 20.05.2009
Вот моя первая рабочая версия драйвера без линуксового фреймворка spi :) загрузка процессора от системы в среднем 0,5 % тогда как раньше один только драйвер съедал 10 %. Теперь не нужно драйвер прописывать в таблице spi. Я совсем отключил у себя поддержку spi в ядре, скорей всего можно будет включить но отключить драйверы которые прописаны в board-... на первом канале spi - оставить только нулевой канал (там у нас dataflash - так что фактически только она и будет работать :) При инициализации паросматривается таблица spi-slave устройств и инициализируются только те каналы на которых есть устройства. Пока есть обнаруженная проблема - не работает как подгружаемый модуль - что-то я не так с дма видимо делаю (ругается на dma_map), пока не знаю как это поправить и вообще что не так - вроде все как в других драйверах делал... Я пока что собираю статически, но если честно мне как модуль он и не нужен. #include "lph88.h" - это переименованный файл atmel_spi.h - не буду его сюда постить - он у всех есть в исходниках - просто скопируйте в директорию драйвера и переименуйте в lph88.h
Цитата /*
* Copyright (C) 2009, Alexander Kudjashev <Kudjashev@gmail.com>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
* Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven
*
* This driver was written to be used with s65 lph88fb lcd
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <mach/gpio.h>
#include "lph88.h"
/* lcd resolution */
#define X_RES 176
#define Y_RES 132
#define B_PP 16
#define MEM_LEN (X_RES * Y_RES * B_PP / 8)
#define SPI_SPEED (12
00
00)
static u8 lcd_init_data[] __initdata = {0x74,0x00,0x00,0x76,0x00,0x01,
0x74,0x00,0x07,0x76,0x00,0x00, 0x74,0x00,0x02,0x76,0x04,0x00, 0x74,0x00,0x04,0x76,0x00,0x00,
0x74,0x00,0x0C,0x76,0x00,0x01, 0x74,0x00,0x0D,0x76,0x06,0x16, 0x74,0x00,0x0E,0x76,0x10,0x10,
0x74,0x00,0x03,0x76,0x00,0x0C, 0x74,0x00,0x0E,0x76,0x2D,0x1F, 0x74,0x00,0x0D,0x76,0x06,0x16,
0x74,0x00,0x01,0x76,0x03,0x15, 0x74,0x00,0x0F,0x76,0x00,0x00, 0x74,0x00,0x0B,0x76,0x00,0x00,
0x74,0x00,0x11,0x76,0x00,0x00, 0x74,0x00,0x06,0x76,0x00,0x00, 0x74,0x00,0x05,0x76,0x00,0x38,
0x74,0x00,0x14,0x76,0xAF,0x00, 0x74,0x00,0x15,0x76,0x00,0x00, 0x74,0x00,0x16,0x76,0x83,0x00,
0x74,0x00,0x17,0x76,0xAF,0x00, 0x74,0x00,0x20,0x76,0x00,0x00, 0x74,0x00,0x30,0x76,0x00,0x00,
0x74,0x00,0x31,0x76,0x04,0x00, 0x74,0x00,0x32,0x76,0x02,0x07, 0x74,0x00,0x33,0x76,0x07,0x00,
0x74,0x00,0x34,0x76,0x00,0x05, 0x74,0x00,0x35,0x76,0x07,0x03, 0x74,0x00,0x36,0x76,0x07,0x07,
0x74,0x00,0x37,0x76,0x00,0x07, 0x74,0x00,0x3A,0x76,0x12,0x00, 0x74,0x00,0x3B,0x76,0x00,0x09,
0x74,0x00,0x07,0x76,0x00,0x05, 0x74,0x00,0x07,0x76,0x00,0x25, 0x74,0x00,0x07,0x76,0x00,0x27,
0x74,0x00,0x07,0x76,0x00,0x37};
static u8 prefix[] = {0x74,0x00,0x21, 0x76,0x00,0x00, 0x74,0x00,0x22, 0x76};
struct transfer {
unsigned len;
dma_addr_t tx_dma;
unsigned cs_active:1;
u8 bits_per_word;
};
struct lph88fb_par {
struct platform_device *pdev;
struct clk *clk;
void __iomem *regs;
u8 *fb_virt;
dma_addr_t fb_phys;
dma_addr_t prefix_dma;
u32 pseudo_palette[16];
u32 csr;
struct transfer tr[5];
u8 index;
};
static struct fb_fix_screeninfo lph88fb_fix __initdata = {
.id = "lph88fb",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
.line_length = X_RES * B_PP / 8,
.accel = FB_ACCEL_NONE,
};
static struct fb_var_screeninfo lph88fb_var __initdata = {
.xres = X_RES,
.yres = Y_RES,
.xres_virtual = X_RES,
.yres_virtual = Y_RES,
.activate = FB_ACTIVATE_NOW,
.vmode = FB_VMODE_NONINTERLACED,
.bits_per_pixel = B_PP,
.red = { 11, 5, 0 },
.green = { 5, 6, 0 },
.blue = { 0, 5, 0 },
.nonstd = 0,
};
static int lph88fb_setcolreg(unsigned regno, unsigned r, unsigned g,
unsigned b, unsigned transp,
struct fb_info *info)
{
if (regno >= 16)
return -EINVAL;
((u32 *) info->pseudo_palette)[regno] =
(r & 0xf800) | (g & 0xfc00) >> 5 | (b & 0xf800) >> 11;
return 0;
}
static struct fb_ops lph88fb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = lph88fb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
static irqreturn_t
spi_interrupt(int irq, void *param)
{
struct lph88fb_par *par = (struct lph88fb_par *)param;
struct transfer *t;
u32 csr = par->csr;
u32 status, len;
spi_writel(par, IDR, SPI_BIT(TXBUFE) | SPI_BIT(ENDTX));
spi_writel(par, PTCR, SPI_BIT(TXTDIS));
status = spi_readl(par, SR);
par->index++;
if(par->index > 4)
par->index = 0;
t = &par->tr[par->index];
csr |= SPI_BF(BITS, t->bits_per_word - 8) | SPI_BF(CSAAT, t->cs_active);
spi_writel(par, CSR0, csr);
len = t->len;
if(t->bits_per_word > 8)
len >>= 1;
spi_writel(par, TPR, t->tx_dma);
spi_writel(par, TCR, len);
spi_writel(par, IER, SPI_BIT(TXBUFE) | SPI_BIT(ENDTX));
spi_writel(par, PTCR, SPI_BIT(TXTEN));
return IRQ_HANDLED;
}
static int __init spi_init(struct lph88fb_par *par)
{
unsigned long bus_hz;
u32 scbr;
/* Initialize the hardware */
at91_set_A_periph(AT91_PIN_PB0, 0); /* SPI1_MISO */
at91_set_A_periph(AT91_PIN_PB1, 0); /* SPI1_MOSI */
at91_set_A_periph(AT91_PIN_PB2, 0); /* SPI1_SPCK */
at91_set_A_periph(AT91_PIN_PB3, 0); /* SPI1_NPCS0 */
spi_writel(par, CR, SPI_BIT(SWRST));
spi_writel(par, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
spi_writel(par, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS) | SPI_BF(PCS, 0x0e));
spi_writel(par, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
spi_writel(par, CR, SPI_BIT(SPIEN));
bus_hz = clk_get_rate(par->clk);
scbr = DIV_ROUND_UP(bus_hz, SPI_SPEED);
par->csr = SPI_BF(SCBR, scbr) | SPI_BIT(NCPHA);
spi_writel(par, CSR0, par->csr);
return 0;
}
static int __init spi_send_poll(struct lph88fb_par *par,
dma_addr_t buff, unsigned len)
{
u32 status;
spi_writel(par, PTCR, SPI_BIT(TXTDIS));
status = spi_readl(par, SR);
spi_writel(par, TPR, buff);
spi_writel(par, TCR, len);
spi_writel(par, PTCR, SPI_BIT(TXTEN));
while(!(spi_readl(par, SR) & (SPI_BIT(ENDTX) | SPI_BIT(TXBUFE))));
return 0;
}
static int __init lcd_init(struct lph88fb_par *par)
{
int i;
dma_addr_t tx_dma;
/* reset lcd controller */
at91_set_gpio_output(AT91_PIN_PB4, 0);
mdelay(1);
at91_set_gpio_value(AT91_PIN_PB4, 1);
mdelay(10);
tx_dma = dma_map_single(NULL, (void *)&lcd_init_data[0],
sizeof(lcd_init_data), DMA_TO_DEVICE);
for(i = 0; i < sizeof(lcd_init_data); i += 3) {
spi_send_poll(par, tx_dma + i, 3);
mdelay(40);
}
dma_unmap_single(NULL, tx_dma, sizeof(lcd_init_data), DMA_TO_DEVICE);
return 0;
}
static int __init start_refresh(struct lph88fb_par *par)
{
struct transfer *t = par->tr;
int i;
u32 status;
spi_writel(par, PTCR, SPI_BIT(TXTDIS));
status = spi_readl(par, SR);
for(i = 0; i < 4; i++) {
t[i].tx_dma = par->prefix_dma + 3 * i;
t[i].bits_per_word = 8;
if(i == 3) {
t[i].len = 1;
t[i].cs_active = 1;
} else {
t[i].len = 3;
t[i].cs_active = 0;
}
}
t[i].tx_dma = par->fb_phys;
t[i].bits_per_word = 16;
t[i].len = MEM_LEN;
t[i].cs_active = 0;
par->index = 4;
spi_interrupt(AT91SAM9260_ID_SPI1, par);
return 0;
}
static int __init lph88fb_probe(struct platform_device *pdev)
{
struct lph88fb_par *par;
struct fb_info *info;
int retval;
retval = -ENOMEM;
info = framebuffer_alloc(sizeof(struct lph88fb_par), &pdev->dev);
if(!info)
return retval;
par = info->par;
par->pdev = pdev;
par->clk = clk_get(NULL, "spi1_clk");
if (IS_ERR(par->clk))
goto err;
clk_enable(par->clk);
par->regs = ioremap(AT91SAM9260_BASE_SPI1, SZ_16K);
if (!par->regs)
goto err1;
spi_init(par);
lcd_init(par);
retval = request_irq(AT91SAM9260_ID_SPI1, spi_interrupt, 0,
pdev->name, par);
if (retval)
goto err2;
retval = -ENOMEM;
par->prefix_dma = dma_map_single(NULL, (void *)&prefix[0],
sizeof(prefix), DMA_TO_DEVICE);
if (dma_mapping_error(NULL, par->prefix_dma))
goto err3;
par->fb_virt = dma_alloc_coherent(NULL, PAGE_ALIGN(MEM_LEN),
&par->fb_phys, GFP_KERNEL);
if(!par->fb_virt)
goto err4;
/* Clear (turn to black) the framebuffer */
memset_io((void __iomem *)par->fb_virt, 0, MEM_LEN);
info->screen_base = (void __iomem *)par->fb_virt;
info->fbops = &lph88fb_ops;
info->var = lph88fb_var;
info->fix = lph88fb_fix;
info->fix.smem_len = MEM_LEN;
info->fix.smem_start = par->fb_phys;
info->screen_size = MEM_LEN;
info->flags = FBINFO_FLAG_DEFAULT;
info->pseudo_palette = par->pseudo_palette;
retval = fb_alloc_cmap(&(info->cmap), 256, 0);
if (retval < 0)
goto err5;
retval = register_framebuffer(info);
if (retval < 0)
goto err6;
platform_set_drvdata(pdev, info);
start_refresh(par);
printk(KERN_INFO "fb%d: %s frame buffer device, %dK of video memory\n",
info->node, info->fix.id, info->fix.smem_len >> 10);
return 0;
err6:
fb_dealloc_cmap(&info->cmap);
err5:
dma_free_coherent(NULL, MEM_LEN, par->fb_virt, par->fb_phys);
err4:
dma_unmap_single(NULL, par->prefix_dma, sizeof(prefix), DMA_TO_DEVICE);
err3:
free_irq(AT91SAM9260_ID_SPI1, par);
err2:
iounmap(par->regs);
err1:
clk_disable(par->clk);
err:
framebuffer_release(info);
return retval;
}
static int lph88fb_remove(struct platform_device *pdev)
{
struct fb_info *info = platform_get_drvdata(pdev);
if (info) {
struct lph88fb_par *par = info->par;
unregister_framebuffer(info);
fb_dealloc_cmap(&info->cmap);
free_irq(AT91SAM9260_ID_SPI1, par);
dma_free_coherent(NULL, MEM_LEN, par->fb_virt, par->fb_phys);
dma_unmap_single(NULL, par->prefix_dma, sizeof(prefix), DMA_TO_DEVICE);
iounmap(par->regs);
clk_disable(par->clk);
framebuffer_release(info);
}
return 0;
}
/* Power down display on reboot, poweroff or halt */
static void lph88fb_shutdown(struct platform_device *pdev)
{
at91_set_gpio_value(AT91_PIN_PB4, 0);
mdelay(1);
at91_set_gpio_value(AT91_PIN_PB4, 1);
mdelay(10);
}
static struct platform_driver lph88fb_driver = {
.probe = lph88fb_probe,
.remove = lph88fb_remove,
.shutdown = lph88fb_shutdown,
.driver = {
.name = "lph88fb",
},
};
static struct platform_device *lph88fb_device;
static int __init lph88fb_init(void)
{
int ret = 0;
ret = platform_driver_register(&lph88fb_driver);
if (!ret) {
lph88fb_device = platform_device_alloc("lph88fb", 0);
if (lph88fb_device)
ret = platform_device_add(lph88fb_device);
else
ret = -ENOMEM;
if (ret) {
platform_device_put(lph88fb_device);
platform_driver_unregister(&lph88fb_driver);
}
}
return ret;
}
static void __exit lph88fb_exit(void)
{
platform_device_unregister(lph88fb_device);
platform_driver_unregister(&lph88fb_driver);
}
module_init(lph88fb_init);
module_exit(lph88fb_exit);
MODULE_AUTHOR("Alexander Kudjashev");
MODULE_DESCRIPTION("lph88 spi fb driver");
MODULE_LICENSE("GPL");
sasa
Регистрация: 20.05.2009
Обновленная версия, решена проблема - теперь может работать и как подгружаемый модуль (обнаружился баг в ядре), немного поменял инициализацию - так стабильней стартует lcd.
Код /*
* Copyright (C) 2009, Alexander Kudjashev <Kudjashev@gmail.com>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
* Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven
*
* This driver was written to be used with s65 lph88 lcd
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <mach/gpio.h>
#include "atmel_spi.h"
/* lcd resolution */
#define X_RES 176
#define Y_RES 132
#define B_PP 16
#define MEM_LEN (X_RES * Y_RES * B_PP / 8)
#define SPI_SPEED (12*1000*1000)
static u8 lcd_init_data[] __initdata = {0x74,0x00,0x00,0x76,0x00,0x01,
0x74,0x00,0x07,0x76,0x00,0x00, 0x74,0x00,0x02,0x76,0x04,0x00, 0x74,0x00,0x04,0x76,0x00,0x00,
0x74,0x00,0x0C,0x76,0x00,0x01, 0x74,0x00,0x0D,0x76,0x06,0x16, 0x74,0x00,0x0E,0x76,0x10,0x10,
0x74,0x00,0x03,0x76,0x00,0x0C, 0x74,0x00,0x0E,0x76,0x2D,0x1F, 0x74,0x00,0x0D,0x76,0x06,0x16,
0x74,0x00,0x01,0x76,0x03,0x15, 0x74,0x00,0x0F,0x76,0x00,0x00, 0x74,0x00,0x0B,0x76,0x00,0x00,
0x74,0x00,0x11,0x76,0x00,0x00, 0x74,0x00,0x06,0x76,0x00,0x00, 0x74,0x00,0x05,0x76,0x00,0x38,
0x74,0x00,0x14,0x76,0xAF,0x00, 0x74,0x00,0x15,0x76,0x00,0x00, 0x74,0x00,0x16,0x76,0x83,0x00,
0x74,0x00,0x17,0x76,0xAF,0x00, 0x74,0x00,0x20,0x76,0x00,0x00, 0x74,0x00,0x30,0x76,0x00,0x00,
0x74,0x00,0x31,0x76,0x04,0x00, 0x74,0x00,0x32,0x76,0x02,0x07, 0x74,0x00,0x33,0x76,0x07,0x00,
0x74,0x00,0x34,0x76,0x00,0x05, 0x74,0x00,0x35,0x76,0x07,0x03, 0x74,0x00,0x36,0x76,0x07,0x07,
0x74,0x00,0x37,0x76,0x00,0x07, 0x74,0x00,0x3A,0x76,0x12,0x00, 0x74,0x00,0x3B,0x76,0x00,0x09,
0x74,0x00,0x07,0x76,0x00,0x05, 0x74,0x00,0x07,0x76,0x00,0x25, 0x74,0x00,0x07,0x76,0x00,0x27,
0x74,0x00,0x07,0x76,0x00,0x37};
static u8 prefix[] __initdata = {0x74,0x00,0x21, 0x76,0x00,0x00, 0x74,0x00,0x22, 0x76};
struct transfer {
unsigned len;
dma_addr_t tx_dma;
/* stay active after transfer */
unsigned cs_active:1;
u8 bits_per_word;
};
struct lph88fb_par {
struct clk *clk;
void __iomem *regs;
u8 *fb_virt;
dma_addr_t fb_phys;
u32 pseudo_palette[16];
u32 csr;
struct transfer tr[5];
u8 index;
};
static struct fb_fix_screeninfo lph88fb_fix __initdata = {
.id = "lph88fb",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
.line_length = X_RES * B_PP / 8,
.accel = FB_ACCEL_NONE,
};
static struct fb_var_screeninfo lph88fb_var __initdata = {
.xres = X_RES,
.yres = Y_RES,
.xres_virtual = X_RES,
.yres_virtual = Y_RES,
.activate = FB_ACTIVATE_NOW,
.vmode = FB_VMODE_NONINTERLACED,
.bits_per_pixel = B_PP,
.red = { 11, 5, 0 },
.green = { 5, 6, 0 },
.blue = { 0, 5, 0 },
.nonstd = 0,
};
static int lph88fb_setcolreg(unsigned regno, unsigned r, unsigned g,
unsigned b, unsigned transp,
struct fb_info *info)
{
if (regno >= 16)
return -EINVAL;
((u32 *) info->pseudo_palette)[regno] =
(r & 0xf800) | (g & 0xfc00) >> 5 | (b & 0xf800) >> 11;
return 0;
}
static struct fb_ops lph88fb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = lph88fb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
static irqreturn_t
spi_interrupt(int irq, void *param)
{
struct lph88fb_par *par = (struct lph88fb_par *)param;
struct transfer *t;
u32 csr = par->csr;
u32 status, len;
spi_writel(par, IDR, SPI_BIT(TXBUFE) | SPI_BIT(ENDTX));
spi_writel(par, PTCR, SPI_BIT(TXTDIS));
status = spi_readl(par, SR);
par->index++;
if(par->index > 4)
par->index = 0;
t = &par->tr[par->index];
csr |= SPI_BF(BITS, t->bits_per_word - 8) | SPI_BF(CSAAT, t->cs_active);
spi_writel(par, CSR0, csr);
len = t->len;
if(t->bits_per_word > 8)
len >>= 1;
spi_writel(par, TPR, t->tx_dma);
spi_writel(par, TCR, len);
spi_writel(par, IER, SPI_BIT(TXBUFE) | SPI_BIT(ENDTX));
spi_writel(par, PTCR, SPI_BIT(TXTEN));
return IRQ_HANDLED;
}
static int __init spi_init(struct lph88fb_par *par)
{
unsigned long bus_hz;
u32 scbr;
/* Initialize the hardware */
/* at91_set_A_periph(AT91_PIN_PB0, 0); SPI1_MISO */
at91_set_A_periph(AT91_PIN_PB1, 0); /* SPI1_MOSI */
at91_set_A_periph(AT91_PIN_PB2, 0); /* SPI1_SPCK */
at91_set_A_periph(AT91_PIN_PB3, 0); /* SPI1_NPCS0 */
spi_writel(par, CR, SPI_BIT(SWRST));
spi_writel(par, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
spi_writel(par, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS) | SPI_BF(PCS, 0x0e));
spi_writel(par, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
spi_writel(par, CR, SPI_BIT(SPIEN));
bus_hz = clk_get_rate(par->clk);
scbr = DIV_ROUND_UP(bus_hz, SPI_SPEED);
par->csr = SPI_BF(SCBR, scbr) | SPI_BIT(NCPHA);
spi_writel(par, CSR0, par->csr);
return 0;
}
static int __init spi_send_poll(struct lph88fb_par *par,
dma_addr_t buff, unsigned len)
{
u32 status;
spi_writel(par, PTCR, SPI_BIT(TXTDIS));
status = spi_readl(par, SR);
spi_writel(par, TPR, buff);
spi_writel(par, TCR, len);
spi_writel(par, PTCR, SPI_BIT(TXTEN));
while(!(spi_readl(par, SR) & (SPI_BIT(ENDTX) | SPI_BIT(TXBUFE))));
return 0;
}
static int __init lcd_init(struct lph88fb_par *par)
{
int i;
u8 *tx_buf = par->fb_virt;
dma_addr_t tx_dma = par->fb_phys;
/* reset lcd controller */
at91_set_gpio_output(AT91_PIN_PB4, 0);
mdelay(1);
at91_set_gpio_value(AT91_PIN_PB4, 1);
mdelay(10);
memcpy(tx_buf, lcd_init_data, sizeof(lcd_init_data));
for(i = 0; i < sizeof(lcd_init_data); i += 3) {
spi_send_poll(par, tx_dma + i, 3);
mdelay(1);
if(tx_buf[i] == 0x76)
switch(tx_buf[i-1]) {
/* power control - need big delay */
case 0x03:
case 0x04:
case 0x0c:
case 0x0d:
case 0x0e:
mdelay(40);
}
}
mdelay(100);
return 0;
}
static int __init start_refresh(struct lph88fb_par *par)
{
struct transfer *t = par->tr;
dma_addr_t prefix_dma = par->fb_phys + MEM_LEN;
int i;
memcpy(par->fb_virt + MEM_LEN, prefix, sizeof(prefix));
for(i = 0; i < 4; i++) {
t[i].tx_dma = prefix_dma + 3 * i;
t[i].bits_per_word = 8;
if(i == 3) {
t[i].len = 1;
t[i].cs_active = 1;
} else {
t[i].len = 3;
t[i].cs_active = 0;
}
}
t[i].tx_dma = par->fb_phys;
t[i].bits_per_word = 16;
t[i].len = MEM_LEN;
t[i].cs_active = 0;
par->index = 4;
spi_interrupt(AT91SAM9260_ID_SPI1, par);
return 0;
}
static int __init lph88fb_probe(struct platform_device *pdev)
{
struct lph88fb_par *par;
struct fb_info *info;
int retval;
retval = -ENOMEM;
info = framebuffer_alloc(sizeof(struct lph88fb_par), &pdev->dev);
if(!info)
return retval;
par = info->par;
par->clk = clk_get(NULL, "spi1_clk");
if (IS_ERR(par->clk))
goto err;
clk_enable(par->clk);
par->regs = ioremap(AT91SAM9260_BASE_SPI1, SZ_16K);
if (!par->regs)
goto err1;
retval = request_irq(AT91SAM9260_ID_SPI1, spi_interrupt, 0,
pdev->name, par);
if (retval)
goto err2;
retval = -ENOMEM;
par->fb_virt = dma_alloc_coherent(NULL, MEM_LEN + sizeof(prefix),
&par->fb_phys, GFP_KERNEL);
if(!par->fb_virt)
goto err3;
spi_init(par);
lcd_init(par);
info->screen_base = (void __iomem *)par->fb_virt;
info->fbops = &lph88fb_ops;
info->var = lph88fb_var;
info->fix = lph88fb_fix;
info->fix.smem_len = MEM_LEN;
info->fix.smem_start = par->fb_phys;
info->screen_size = MEM_LEN;
info->flags = FBINFO_FLAG_DEFAULT;
info->pseudo_palette = par->pseudo_palette;
retval = fb_alloc_cmap(&(info->cmap), 256, 0);
if (retval < 0)
goto err4;
memset(par->fb_virt, 0, MEM_LEN);
retval = register_framebuffer(info);
if (retval < 0)
goto err5;
platform_set_drvdata(pdev, info);
start_refresh(par);
printk(KERN_INFO "fb%d: %s frame buffer device, %dK of video memory\n",
info->node, info->fix.id, info->fix.smem_len >> 10);
return 0;
err5:
fb_dealloc_cmap(&info->cmap);
err4:
dma_free_coherent(NULL, MEM_LEN + sizeof(prefix), par->fb_virt, par->fb_phys);
err3:
free_irq(AT91SAM9260_ID_SPI1, par);
err2:
iounmap(par->regs);
err1:
clk_disable(par->clk);
err:
framebuffer_release(info);
return retval;
}
static int lph88fb_remove(struct platform_device *pdev)
{
struct fb_info *info = platform_get_drvdata(pdev);
if (info) {
struct lph88fb_par *par = info->par;
unregister_framebuffer(info);
fb_dealloc_cmap(&info->cmap);
free_irq(AT91SAM9260_ID_SPI1, par);
clk_disable(par->clk);
dma_free_coherent(NULL, MEM_LEN + sizeof(prefix),
par->fb_virt, par->fb_phys);
iounmap(par->regs);
framebuffer_release(info);
}
return 0;
}
/* Power down display on reboot, poweroff or halt */
static void lph88fb_shutdown(struct platform_device *pdev)
{
at91_set_gpio_value(AT91_PIN_PB4, 0);
mdelay(1);
at91_set_gpio_value(AT91_PIN_PB4, 1);
mdelay(10);
}
static struct platform_driver lph88fb_driver = {
.probe = lph88fb_probe,
.remove = lph88fb_remove,
.shutdown = lph88fb_shutdown,
.driver = {
.name = "lph88fb",
},
};
static struct platform_device *lph88fb_device;
static int __init lph88fb_init(void)
{
int ret = 0;
ret = platform_driver_register(&lph88fb_driver);
if (!ret) {
lph88fb_device = platform_device_alloc("lph88fb", 0);
if (lph88fb_device)
ret = platform_device_add(lph88fb_device);
else
ret = -ENOMEM;
if (ret) {
platform_device_put(lph88fb_device);
platform_driver_unregister(&lph88fb_driver);
}
}
return ret;
}
static void __exit lph88fb_exit(void)
{
platform_device_unregister(lph88fb_device);
platform_driver_unregister(&lph88fb_driver);
}
module_init(lph88fb_init);
module_exit(lph88fb_exit);
MODULE_AUTHOR("Alexander Kudjashev");
MODULE_DESCRIPTION("lph88 spi fb driver");
MODULE_LICENSE("GPL");
sasa
Регистрация: 20.05.2009
С последним драйвером попробовал mplayer - работает :) Пререкодировал видео c lavc в mpeg4 176х132 битрэйт 256 для видео и 96 для звука и тут странное дело - с опцией -nosound все летает, процессор загружен на динамичных сценах максимум на 40 % а в среднем 20-30 %, запускаю со звуком и сразу тормоза. Система загружена под завязку. Неужели декодирование mp3 потока так съедает процессор ? что-то мне не верится... madplay всего процентов 20 съедал - а тут все 60% и mplayer пишет что система слишком слаба для запуска этого ролика... Но в общем новый драйвер ведет себя отлично :) Я даже не ожидал что можно будет смотреть avi в mpeg4. К сожалению я сейчас на gprs - не смогу выложить видео, будет возможность - выложу. Да и звуком сейчас не могу насладться - аудиокодек не распаян пока что на новом переходнике, данные летят в пустоту :)
sasa
Регистрация: 20.05.2009
Какая-то ерунда - mplayer на воспроизведении звука съедает весь процессор... Для эксперимента взял обычный mp3 файл, madplay съедает 20-30 % а mplayer на том же файле грузит процессор под завязку - 100%.
sasa
Регистрация: 20.05.2009
rw9uao
Группа: Клиенты
Пункты: 6973
Регистрация: 26.03.2009