linux驱动I2C/SPI——misc混杂设备版【普通驱动】

misc的方式写驱动相对简单,最底层的还是操作寄存器,和单片机同样的原理。代码直接贴出来,非常时候新手学习。

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>


#define GPIO_4_BASE 0x20180000
#define SDA		(1 << 3)    /* GPIO 4_3 */
#define SCL		(1 << 4)    /* GPIO 4_4 */
#define GPIO_SPI_SCL_REG	IO_ADDRESS(GPIO_4_BASE + 0x040)
#define GPIO_SPI_SDA_REG	IO_ADDRESS(GPIO_4_BASE + 0x020)
#define GPIO_SPI_SDASCL_REG	IO_ADDRESS(GPIO_4_BASE + 0x060)

#define GPIO_4_DIR 			IO_ADDRESS(GPIO_4_BASE + 0x400)

#define GPIO_3_BASE 0x20170000
#define CS		(1 << 2)    /* GPIO 3_3 */
#define DC		(1 << 5)    /* GPIO 3_5 */
#define GPIO_SPI_CS_REG		IO_ADDRESS(GPIO_3_BASE + 0x020)
#define GPIO_SPI_DC_REG		IO_ADDRESS(GPIO_3_BASE + 0x080)

#define GPIO_3_DIR 			IO_ADDRESS(GPIO_3_BASE + 0x400)

#define HW_REG(reg)		*((volatile unsigned int *)(reg))

#define SEND_COMMAND	0x01
#define SEND_DATA		0x03

static void spi_clr(unsigned char whichline)
{
	unsigned char regvalue;

	if(whichline == SCL){
		regvalue = HW_REG(GPIO_4_DIR);
		regvalue |= SCL;
		HW_REG(GPIO_4_DIR) = regvalue;

		HW_REG(GPIO_SPI_SCL_REG) = 0;
	}else if(whichline == SDA){
		regvalue = HW_REG(GPIO_4_DIR);
		regvalue |= SDA;
		HW_REG(GPIO_4_DIR) = regvalue;

		HW_REG(GPIO_SPI_SDA_REG) = 0;
	}else if(whichline == (SDA|SCL)){
		regvalue = HW_REG(GPIO_4_DIR);
		regvalue |= (SCL|SDA);
		HW_REG(GPIO_4_DIR) = regvalue;

		HW_REG(GPIO_SPI_SDASCL_REG) = 0;
	}else if(whichline == CS){
		regvalue = HW_REG(GPIO_3_DIR);
		regvalue |= CS;
		HW_REG(GPIO_3_DIR) = regvalue;

		HW_REG(GPIO_SPI_CS_REG) = 0;
	}else if(whichline == DC){
		regvalue = HW_REG(GPIO_3_DIR);
		regvalue |= DC;
		HW_REG(GPIO_3_DIR) = regvalue;

		HW_REG(GPIO_SPI_DC_REG) = 0;
	}else{
		printk("Error input.\n");
	}
}
static void spi_set(unsigned char whichline)
{
	unsigned char regvalue;

	if(whichline == SCL){
		regvalue = HW_REG(GPIO_4_DIR);
		regvalue |= SCL;
		HW_REG(GPIO_4_DIR) = regvalue;

		HW_REG(GPIO_SPI_SCL_REG) = SCL;
	}else if(whichline == SDA){
		regvalue = HW_REG(GPIO_4_DIR);
		regvalue |= SDA;
		HW_REG(GPIO_4_DIR) = regvalue;

		HW_REG(GPIO_SPI_SDA_REG) = SDA;
	}else if(whichline == (SDA|SCL)){
		regvalue = HW_REG(GPIO_4_DIR);
		regvalue |= (SCL|SDA);
		HW_REG(GPIO_4_DIR) = regvalue;

		HW_REG(GPIO_SPI_SDASCL_REG) = (SDA|SCL);
	}else if(whichline == CS){
		regvalue = HW_REG(GPIO_3_DIR);
		regvalue |= CS;
		HW_REG(GPIO_3_DIR) = regvalue;

		HW_REG(GPIO_SPI_CS_REG) = 0xff;
	}else if(whichline == DC){
		regvalue = HW_REG(GPIO_3_DIR);
		regvalue |= DC;
		HW_REG(GPIO_3_DIR) = regvalue;

		HW_REG(GPIO_SPI_DC_REG) = 0xff;
	}else{
		printk("Error input.\n");
	}
}
static void spi_send_byte(unsigned char c,unsigned char dir)
{
	unsigned char temp,i;
	local_irq_disable();
	spi_clr(CS);
	if(dir == 1)
		spi_set(DC);//data
	else
		spi_clr(DC);//command
	temp = c;
	for(i=0; i<8; i++){
		if(temp&0x80)
			spi_set(SDA);
		else
			spi_clr(SDA);
		temp = temp<<1;
		spi_clr(SCL);
		udelay(2);
		spi_set(SCL);
		udelay(2);
	}
	spi_set(SCL);
	spi_set(CS);
}
int gpiospi_open(struct inode * inode, struct file * file)
{
    return 0;
}
int gpiospi_close(struct inode * inode, struct file * file)
{
    return 0;
}
static long gpiospi_ioctl(struct file* file, unsigned int cmd, unsigned long arg)
{
	
	switch(cmd){
	case SEND_COMMAND:
		spi_send_byte((unsigned char)arg,0);
		break;
	case SEND_DATA:
		spi_send_byte((unsigned char)arg,1);
		break;
	default :
		return -1;
	}	
	return 0;
}

static struct file_operations gpiospi_fops =
{
	.owner      = THIS_MODULE,
	.unlocked_ioctl = gpiospi_ioctl,
	.open       = gpiospi_open,
    .release    = gpiospi_close,
};
static struct miscdevice gpiospi_dev =
{
	MISC_DYNAMIC_MINOR,
	"gpio_spi",
	&gpiospi_fops,
};

static int __init gpio_spi_init(void)
{
	int ret;
	
	ret = misc_register(&gpiospi_dev);
	if(ret != 0)
	{
		printk("could not register gpio_spi device\n");
		return -1;
	}

	printk("load gpio_spi.ko ok!\n");
	return ret;
}
static void __exit gpio_spi_exit(void)
{
	misc_deregister(&gpiospi_dev);
	printk("I'll be leaving, bye!\n");
}
module_init(gpio_spi_init);
module_exit(gpio_spi_exit);
MODULE_LICENSE("GPL");

非常简单的结构,连probe都没有。最核心的是misc_register和misc_deregister,基本就是填充结构体

驱动的open和write方法内没有内容,所有功能放在了ioctl内

另外一种驱动方法:嵌入了系统的I2c总线,稍微复杂一点,因为使用了平台驱动,调用了系统的框架,多了probe等方法,这样的好处是方便移植驱动。I2C和SPi原理类似,可以相互参考。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值