根据之前说过的 SPI 驱动的框架,在我们添加 SPI 设备驱动的时候需要与 SPI Master 完成匹配,通过 spi_register_board_info 进行注册。
构造设备
static struct spi_board_info spi_info_mini2440 = {
.modalias = "oled", /* 对应的 spi_driver 名字也是 "oled" */
.max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */
.bus_num = 0, /* mini2440 里 OLED 接在 SPI CONTROLLER 0 */
.mode = SPI_MODE_0,
.chip_select = S3C2410_GPG(1), /* oled_cs, 它的含义由 spi_master 确定 */
.platform_data = (const void *)S3C2410_GPF(3) ,/* oled_dc, 它在 spi_driver 里使用 */
}
然后调用 spi_register_board_info 函数完成注册。
内核没有实现对 spi_register_board_info 进行 export_symbol 导出,我们不能在模块中来调用,所以需要修改对应 Makefile 将这个文件编进内核。
设备驱动
/* 构建 spi_driver 结构体 */
static struct spi_driver spi_oled_drv = {
.driver = {
.name = "oled",
.owner = THIS_MODULE,
},
.probe = spi_oled_probe,
.remove = __devexit_p(spi_oled_remove),
};
/* probe 函数 */
static int __devinit spi_oled_probe(struct spi_device *spi)
{
spi_oled_dev = spi;
spi_oled_dc_pin = (int)spi->dev.platform_data;
/* 配置 dc、cs 引脚为 output */
s3c2410_gpio_cfgpin(spi_oled_dc_pin, S3C2410_GPIO_OUTPUT);
s3c2410_gpio_cfgpin(spi->chip_select, S3C2410_GPIO_OUTPUT);
/* 供 copy_from_user 使用 */
ker_buf = kmalloc(4096, GFP_KERNEL);
/* 注册一个 file_operations */
major = register_chrdev(0, "oled", &oled_ops);
class = class_create(THIS_MODULE, "oled");
/* 为了让 mdev 根据这些信息来创建设备节点 */
device_create(class, NULL, MKDEV(major, 0), NULL, "oled"); /* /dev/oled */
return 0;
}
probe 函数中通过 register_chrdev 创建一个字符设备,然后通过其 ioctl、write 调用 oled 的初始化和写内存函数来完成对 oled 的操作。
最后调用 spi_register_driver 函数完成设备驱动的注册。
测试程序
/* page: 0-7
* col : 0-127
* 字符: 8x16象素
*/
void OLEDPutChar(int fd, int page, int col, char c)
{
int i = 0;
/* 得到字模 */
const unsigned char *dots = oled_asc2_8x16[c - ' '];
/* 发给OLED */
OLEDSetPos(page, col);
ioctl(fd, OLED_CMD_CLEAR_PAGE, page);
ioctl(fd, OLED_CMD_SET_POS, page | (col << 8));
/* 发出8字节数据 */
for (i = 0; i < 8; i++)
OLEDWriteDat(dots[i]);
write(fd, &dots[0], 8);
OLEDSetPos(page+1, col);
ioctl(fd, OLED_CMD_CLEAR_PAGE, page+1);
ioctl(fd, OLED_CMD_SET_POS, (page+1) | (col << 8));
/* 发出8字节数据 */
for (i = 0; i < 8; i++)
OLEDWriteDat(dots[i+8]);
write(fd, &dots[8], 8);
}
通过调用 ioctl 与 write 接口就可以完成对 oled 的测试。