背景
项目需要,f1c100s的接口本身只有rgb接口,考虑到屏的成本,使用的spi接口屏,但是100s的tina系统没有支持spi接口屏的显示
芯片:f1c100s
系统:tina(linux-3.10)
实现
一、代码下载:
在内核目录 linux-3.10/driver/video/ 获取:
git clone https://github.com/notro/fbtft
二、修改:
a.linux-3.10/drivers/video/Kconfig
source "drivers/video/fbtft/Kconfig"
b.f1c100s\tina\lichee\linux-3.10\drivers\video\Makefile
obj-y += fbtft/
三、修改spi屏配置:
源码路径(目前修改的是下面驱动屏代码):
f1c100s\tina\lichee\linux-3.10\drivers\video\fbtft\fb_hx8340bn.c
1.修改分辨率大小:
#define WIDTH 240
#define HEIGHT 320
2.修改初始化代码:
static int init_display(struct fbtft_par *par)
{
fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
par->fbtftops.reset(par);
write_reg(par,0xfe);
write_reg(par,0xef);
write_reg(par,0x36,0x48);
write_reg(par,0x3a,0x05);
write_reg(par,0x86,0x98);
。。。。。
write_reg(par,0x89,0x13);
}
3.修改对应spi接口屏的配置
static struct fbtft_display display = {
.regwidth = 8, /*spi屏寄存器的位宽*/
.width = WIDTH,
.height = HEIGHT,
.txbuflen = TXBUFLEN,
.gamma_num = 2,
.gamma_len = 15,
.gamma = DEFAULT_GAMMA,
.fbtftops = {
.init_display = init_display,
.set_addr_win = set_addr_win, /*窗口设置函数,根据接口屏设置,一般不用修改, 当分辨率对,窗口显示不全是可以考虑此处*/
/*.set_var = set_var,*/ /*涉及到显示旋转,一般可注释掉*/
.set_gamma = set_gamma,
},
};
FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8340bn", &display); /*himax,hx8340bn 跟设备树对应上 compatible*/
4.修改窗口设置函数(改屏需要修改)
void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
{
fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
write_reg(par, 0x2a, (xs>>8), xs, (xe>>8), xe);
// ipslcd_write_command(spi, 0x2a); //列地址设置
// ipslcd_write_data8(spi, (x1>>8));
// ipslcd_write_data8(spi, x1);
// ipslcd_write_data8(spi, (x2>>8));
// ipslcd_write_data8(spi, x2);
write_reg(par, 0x2b, (ys>>8), ys, (ye>>8), ye);
// ipslcd_write_command(spi, 0x2b); //行地址设置
// ipslcd_write_data8(spi, (y1>>8));
// ipslcd_write_data8(spi, y1);
// ipslcd_write_data8(spi, (y2>>8));
// ipslcd_write_data8(spi, y2);
write_reg(par, 0x2c);
// ipslcd_write_command(spi, 0x2c); //存储器写
// write_reg(par, FBTFT_CASET, 0x00, xs, 0x00, xe);
// write_reg(par, FBTFT_RASET, 0x00, ys, 0x00, ye);
// write_reg(par, FBTFT_RAMWR);
}
四、添加设备树配置:
hy28a@0{
compatible = "himax,hx8340bn";
reg = <0>;
status = "okay";
spi-max-frequency = <50000000>;
spi-cpol;
spi-cpha;
rotate = <0>;
bgr;
fps = <50>;
buswidth = <8>;
reset-gpios = <&pio PE 10 1 1 1 1>;
dc-gpios = <&pio PE 11 1 1 1 1>;
bl-gpios = <&pio PE 12 1 1 1 1>;
debug = <1>;
};
五、修改fbtft框架代码(针对linux-3.10的修改):
源码路径:lichee\linux-3.10\drivers\video\fbtft\fbtft-core.c
1.修改设备树获取函数
static int fbtft_request_gpios_dt(struct fbtft_par *par)
{
int i;
int ret;
if (!par->info->device->of_node)
return -EINVAL;
// ret = fbtft_request_one_gpio(par, "reset-gpios", 0, &par->gpio.reset);
// if (ret)
// return ret;
// ret = fbtft_request_one_gpio(par, "dc-gpios", 0, &par->gpio.dc);
// if (ret)
// return ret;
// ret = fbtft_request_one_gpio(par, "rd-gpios", 0, &par->gpio.rd);
// if (ret)
// return ret;
// ret = fbtft_request_one_gpio(par, "wr-gpios", 0, &par->gpio.wr);
// if (ret)
// return ret;
// ret = fbtft_request_one_gpio(par, "cs-gpios", 0, &par->gpio.cs);
// if (ret)
// return ret;
// ret = fbtft_request_one_gpio(par, "latch-gpios", 0, &par->gpio.latch);
// if (ret)
// return ret;
// for (i = 0; i < 16; i++) {
// ret = fbtft_request_one_gpio(par, "db-gpios", i,
// &par->gpio.db[i]);
// if (ret)
// return ret;
// ret = fbtft_request_one_gpio(par, "led-gpios", i,
// &par->gpio.led[i]);
// if (ret)
// return ret;
// ret = fbtft_request_one_gpio(par, "aux-gpios", i,
// &par->gpio.aux[i]);
// if (ret)
// return ret;
// }
par->gpio.reset= of_get_named_gpio(par->info->device->of_node, "reset-gpios", 0);
if(par->gpio.reset < 0)
{
printk("can't get res-gpios");
return -EINVAL;
}
par->gpio.dc = of_get_named_gpio(par->info->device->of_node, "dc-gpios", 0);
if(par->gpio.dc < 0)
{
printk("can't get dc-gpios");
return -EINVAL;
}
par->gpio.bl = of_get_named_gpio(par->info->device->of_node, "bl-gpios", 0);
if(par->gpio.bl < 0)
{
printk("can't get bl-gpios");
return -EINVAL;
}
ret = gpio_request(par->gpio.reset, "spi-lcd-rst-gpio");
if (ret < 0) {
printk("gpio %d request fail!\n", par->gpio.reset);
return -1;
}
ret = gpio_request(par->gpio.dc, "spi-lcd-dc-gpio");
if (ret < 0) {
printk("gpio %d request fail!\n", par->gpio.dc);
return -1;
}
ret = gpio_request(par->gpio.bl, "spi-lcd-bl-gpio");
if (ret < 0) {
printk("gpio %d request fail!\n", par->gpio.bl);
return -1;
}
/* 3、设置GPIO初始化输出 */
ret = gpio_direction_output(par->gpio.reset, 1);
if(ret < 0)
{
printk("can't set res_gpios!\r\n");
}
ret = gpio_direction_output(par->gpio.dc, 1);
if(ret < 0)
{
printk("can't set dc_gpios!\r\n");
}
ret = gpio_direction_output(par->gpio.bl, 1);
if(ret < 0)
{
printk("can't set dc_gpios!\r\n");
}
return 0;
}
2.修改复位函数(根据spi屏的时序来修改)
void fbtft_reset(struct fbtft_par *par)
{
printk("%s %d %s\n",__FILE__,__LINE__,__FUNCTION__);
if (par->gpio.reset == -1)
return;
fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__);
printk("%s %d %s\n",__FILE__,__LINE__,__FUNCTION__);
gpio_set_value(par->gpio.reset, 1);
msleep(50);
gpio_set_value(par->gpio.reset, 0);
msleep(50);
gpio_set_value(par->gpio.reset, 1);
msleep(120);
}
3.修改spi结构体成员变量(添加背光控制引脚)
struct fbtft_par {
struct spi_device *spi;
struct platform_device *pdev;
struct fb_info *info;
struct fbtft_platform_data *pdata;
u16 *ssbuf;
u32 pseudo_palette[16];
struct {
void *buf;
dma_addr_t dma;
size_t len;
} txbuf;
u8 *buf;
u8 startbyte;
struct fbtft_ops fbtftops;
spinlock_t dirty_lock;
unsigned dirty_lines_start;
unsigned dirty_lines_end;
struct {
int reset;
int dc;
int rd;
int bl; ==》添加背光控制引脚
int wr;
int latch;
int cs;
int db[16];
int led[16];
int aux[16];
} gpio;
int *init_sequence;
struct {
struct mutex lock;
unsigned long *curves;
int num_values;
int num_curves;
} gamma;
unsigned long debug;
bool first_update_done;
struct timespec update_time;
bool bgr;
void *extra;
};
**最后编译不要忘了选上配置哈,大功告成啦!!!**