参考:排名不分先后顺序
1、设备树学习之(十二)LCD驱动
2、exynos4412 的FIMD 介绍
3、Exynos4412——LCD驱动
4、【TINY4412】LINUX移植笔记:(27)设备树LCD驱动
本人使用的开发板为itop4412开发板,因为官方提供的Linux4.14的内核并没有提供4.3寸LCD屏的设备树和驱动,但是直接烧录镜像发现屏幕是可以被点亮的,萌发移植lcd驱动的念头。对于移植来说,无论哪家的开发板,同一个soc,片上外设情况都是相同的,可以借鉴。
本工程源码已打包进内核,使用gitee托管:地址
开始移植
移植的时候,搜索了大量的资料,决定采用设备树的方式进行驱动移植。关于4412这款soc的lcd设备树,有不少前辈做了许多相关的工作。顺便我也学习了一下设备树的相关知识。
在设备树上添加LCD设备:
/* 供电 */
powerctrl{
compatible = "powerctrl-gpio";
pinctrl-names = "default";
pinctrl-0 = <&power_ctrl>,<&lcd_ctrl>;
gpios = <&gpl0 4 0>,<&gpl1 0 0>,<&gpd0 1 0>,<&gpl0 2 0>;
usb-ctl = <&gpm2 4 0>,<&gpm3 3 0>;
me3630-ctl = <&gpc0 4 0>,<&gpz 6 0>;
};
/* LCD设备 */
lcd_4_3@11C00000 {
compatible = "itop4412, lcd_4_3";
reg = <0x11C00000 0x20c0 0x10010210 0x08 0x10023c80 0x04 0x1003c000 0x1000>;
pinctrl-names = "default";
pinctrl-0 = <&lcd_4_3>;
clocks = <&clock CLK_FIMD0 &clock CLK_ACLK160>;
clock-names = "fimd0","aclk160";
};
对应的pin-ctl:
&pinctrl_0 {
lcd_4_3:lcd {
samsung,pins = "gpf0-0", "gpf0-1", "gpf0-2", "gpf0-3", "gpf0-4",
"gpf0-5", "gpf0-6","gpf0-7", "gpf1-0", "gpf1-1",
"gpf1-2", "gpf1-3", "gpf1-4", "gpf1-5", "gpf1-6",
"gpf1-7", "gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3",
"gpf2-4", "gpf2-5", "gpf2-6","gpf2-7", "gpf3-0",
"gpf3-1", "gpf3-2", "gpf3-3";
samsung,pin-function = <2>;
samsung,pin-pud = <0>;
samsung,pin-drv = <0>;
};
};
&pinctrl_1 {
power_ctrl:power_ctrl{
samsung,pins = "gpl0-4","gpl1-0","gpl0-2";
samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>;
samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};
};
添加power驱动,移植自官方power.c:
可以编译进内核,也可以编译成模块加载
/*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/of_gpio.h>
#define DEVICE_NAME "power_ctl"
#define DRIVER_NAME "power_ctl"
//#define POWER_GPIO 100//IMX_GPIO_NR(1, 19)
uint32_t POWER_GPIO = 0;
uint32_t LVDS_GPIO = 0;
uint32_t PWM_GPIO = 0;
uint32_t TP_GPIO = 0;
uint32_t USB_RST = 0;
uint32_t USB_CON = 0;
uint32_t ME3630_POW = 0;
uint32_t ME3630_RST = 0;
static int power_open(struct inode *inode, struct file *file) {
return 0;
}
static int power_close(struct inode *inode, struct file *file) {
return 0;
}
static long power_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg)
{
printk("%s: cmd = %d\n", __FUNCTION__, cmd);
switch(cmd) {
case 0:
gpio_set_value(POWER_GPIO, 0);
break;
case 1:
gpio_set_value(POWER_GPIO, 1);
break;
default:
return -EINVAL;
}
return 0;
}
static ssize_t power_write(struct file *filp, const char __user *buffer, size_t count, loff_t *ppos)
{
char str[20];
memset(str, 0, 20);
if(copy_from_user(str, buffer, count))
{
printk("Error\n");
return -EINVAL;
}
printk("%s", str);
#if 1
if(!strncmp(str, "1", 1))
gpio_set_value(POWER_GPIO, 1);
else
gpio_set_value(POWER_GPIO, 0);
#endif
return count;
}
static struct file_operations power_ops = {
.owner = THIS_MODULE,
.open = power_open,
.release = power_close,
.unlocked_ioctl = power_ioctl,
.write = power_write,
};
static struct miscdevice power_misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &power_ops,
};
static int power_probe(struct platform_device *pdev)
{
int ret;
struct device_node *np = pdev->dev.of_node;
POWER_GPIO = of_get_named_gpio(np, "gpios", 0);
if (POWER_GPIO == -EPROBE_DEFER)
return POWER_GPIO;
if (POWER_GPIO < 0) {
dev_err(&pdev->dev, "error acquiring power gpio: %d\n", POWER_GPIO