上一篇帖子讲i2c的东西,说实话一个呼吸灯的东西真的没什么好讲,本来调通了之后发几张图一起高潮一下,然而发现并没有什么卵用,基本留出了测试点,后续的东西都差不多。如果有同学这面有什么问题加我好友咱们私下沟通,在3399上面调通了协议,后面有点不想搞了,因为着急想玩安卓7.0,最近也在下载源码,编译什么的又搞了很久,也没搞出什么名堂(心累),然后在联发科的mt6735平台实验了一下(想要源码的私信我)。
接下来准备搞spi了。。其实我也好想搞摄像头,然而我这个焊工,飞线非死不可。。我看还几个同学和我说这个板子支持几路摄像头,我也挺想试试的,别急。。。稳一稳(现在手头上工作也比较急,等有时间了拿出来单独玩耍一下)。
书归正传,咱们开始说spi吧,我看到了rk3399里讲的通过设备树添加设备到内核中,当然设备树是可行的,但是wiki里面讲的比较全(其实坑很多的),我就不用那种方法了。
- int assist_spi_lcd_module_init(void)
- {
- // struct device *dev;
- pr_info("assist_spi_lcd_module_initn");
- spi_register_board_info(st7789v_spi_board_devs, ARRAY_SIZE(st7789v_spi_board_devs));
- spi_register_driver(&st7789v_spi_driver_l);
- //spi_register_driver(&st7789v_spi_driver_r);
-
- st7789v_add_fs();
- return 0;
- }
- void assist_spi_lcd_module_exit(void)
- {
- pr_info("assist_spi_lcd_module_exit suren");
- spi_unregister_driver(&st7789v_spi_driver_l);
- //spi_unregister_driver(&st7789v_spi_driver_r);
- st7789v_del_fs();
- st7789v_free_buffer();
- st7789v_power_down();
- st7789v_gpio_exit();
-
- }
- module_init(assist_spi_lcd_module_init);
- module_exit(assist_spi_lcd_module_exit);
复制代码
老规矩还是注册出口和入口,入口是加载这个驱动模块时被运行的代码,然后呢,我们就要看init函数里面了,我们使用 spi_register_board_info函数来注册设备到内核,如果你使用设备树dts可以省略这一步,然后,注册spi的驱动
- static struct spi_board_info st7789v_spi_board_devs[] __initdata = {
- [0] = {
- .modalias = "st7789v_l",
- #if 1
- .max_speed_hz = 50 *1000 * 1000,//50 * 1000 *1000, // 25MHz
- #else
- .max_speed_hz = 56 * 1000 *1000, // MAX 27MHz
- #endif
- .bus_num = 0,
- .chip_select = 0,
- .mode = SPI_MODE_3,
- #if 0
- .irq = 3,
- #endif
- },
- };
- struct spi_device_id spi_id_7789_table = { "st7789v_l", 0 };
- static struct spi_driver st7789v_spi_driver_l = {
- .driver = {
- .name = "st7789v_l",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = st7789v_spi_probe_l,
- .remove = st7789v_spi_remove,
- .id_table = &spi_id_7789_table,
- };
复制代码
驱动和设备名字相同,或者id_table里面搞一个和设备名字一样的,如果你使用的是设备树,要完成driver成员的of_match_table,把名字和设备树中的 compatible相同就可以了,注册完设备之后,如果设备和驱动匹配没有问题呢,就会进入probe函数了。
- static int st7789v_spi_probe_l(struct spi_device *spi)
- {
- int ret = 0;
- //int set_bl;
- assist_lcd_spi_device_l = *spi;
- printk("st7789v_spi_probe_l st7789v_max_speed %d"
- ,spi->max_speed_hz);
- printk("chip_select %d--master %dn",spi->chip_select,spi->master->bus_num);// bits_per_word %s mode %u
- printk("bits_per_word %d---mode %dn",spi->bits_per_word,spi->mode);
- printk("bits_per_word %d---mode %dn",assist_lcd_spi_device_l.bits_per_word,assist_lcd_spi_device_l.mode);
- memset(&assist_lcd_info, 0, sizeof(assist_lcd_info_t));
- assist_lcd_info.dev_l = &spi->dev;
- SPI_Init(&assist_lcd_spi_device_l);
- #if USED_FORE_LINE_8BIT_MODE
- ret = gpio_request(SPI_MISO_PIN,"SPI_LCD_MISO_WR");
- if(ret < 0){
- printk("gpio quest fail %d n",SPI_MISO_PIN);
- return -1;
- }
- gpio_direction_output(SPI_MISO_PIN, 1);
- #endif
- ret = gpio_request(LCD_CS_R_PIN,"LCD_CS_R_PIN");
- if(ret < 0){
- printk("gpio quest fail %d n",LCD_CS_R_PIN);
- return -1;
- }
- gpio_direction_output(LCD_CS_R_PIN, 1);
- ret = gpio_request(LCD_CS_L_PIN,"LCD_CS_L_PIN");
- if(ret < 0){
- printk("gpio quest fail %d n",LCD_CS_L_PIN);
- return -1;
- }
- gpio_direction_output(LCD_CS_L_PIN, 1);
- ret = gpio_request(LCD_RST_PIN,"SPI_LCD_RST");
- if(ret < 0){
- printk("LCD_RST_PIN gpio quest fail %d n",LCD_RST_PIN);
- return -1;
- }
- gpio_direction_output(LCD_RST_PIN, 1);
- ret = gpio_request(LCD_BL_PIN,"SPI_LCD_BL");
- if(ret < 0){
- printk("gpio quest fail %d n",LCD_BL_PIN);
- return -1;
- }
- gpio_direction_output(LCD_BL_PIN, 0);
- ret = gpio_request(GPIO_RESVE3,"GPIO_RESVE3");
- if(ret < 0){
- printk("gpio quest fail %d n",GPIO_RESVE3);
- return -1;}
- }
复制代码
probe函数里面最重要的事情莫过于注册对应的gpio和初始化spi总线,spi是不需要设备就可以实现波形的输出的,这就很开心不用费事去连接种种麻烦的线(不过我还是给从设备的线都引出来了)。其实我一点都不想讲硬件原理,因为我硬件水一匹,作为一个驱动工程师,我都不好意思说哈哈,算了,继续。。不同平台的优先级是不一样的,有的在注册设备的时候直接就有默认配置,dts里面也会默认的配置,可以不配置就直接用(部分平台哈),在全志和mtk平台dts的优先级非常低,rk3399我没有用dts也是有这个因素的,然后在probe中除了配置gpio意外,要初始化一些东西,像上升下降沿的触发和保持时间
- static int SPI_Init(struct spi_device *db)
- {
- struct mt_chip_conf* spi_par; // added 2015-12-3
- spi_par = (struct mt_chip_conf *) db->controller_data;
- spi_par->setuptime = 15;//20;//15;
- spi_par->holdtime = 15;// 20;
- spi_par->high_time = 2; // 500 //10--6m 15--4m 20--3m 30--2m [ 60--1m 120--0.5m 300--0.2m]
- spi_par->low_time = 2; //500
- spi_par->cs_idletime = 20; //20
- spi_par->rx_ml*** = 1;
- spi_par->tx_ml*** = 1;
- spi_par->tx_endian = 0;
- spi_par->rx_endian = 0;
- spi_par->cpol = 0;
- spi_par->cpha = 0;
- spi_par->com_mod = DMA_TRANSFER;
- spi_par->pause = 0;
- spi_par->finish_intr = 1;
- spi_par->deassert = 0;
- spi_setup(db);
- return 0;
- }
复制代码
high_time,low_time决定了他的频率,我感觉这样设置要比单纯设置频率稳定的多(毕竟我啥也不懂,多设置点东西总是没错的)。然后写个大概的测试程序,不听的刷一个固定数据。
看一下 波形,这个频率设置的低一些,方便示波器抓。。下面是数据,上面是时钟脚的波形,先这样,有后续想调试spi的同学欢迎沟通交流哈
|