//#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/irq.h>
#include <mach/gpio.h>
#include <plat/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <mach/map.h>
#include <plat/devs.h>
#include <plat/regs-timer.h>
#include <plat/gpio-bank-m.h>
#include <plat/gpio-bank-p.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
//****************************************************************//
#define DEVICE_NAME "sensor"
#define SENSOR_MAJOR 235
//****************************************************************//
//HM5883L register define
#define SENSOR_HM5883L 0
#define HM5883L_SLAVE_ADDRESS 0x3C
#define HM5883L_CONFIG_A 0x00
#define HM5883L_CONFIG_B 0x01
#define HM5883L_MODE 0x02
#define HM5883L_DATA_X_H 0x03
#define HM5883L_DATA_X_L 0x04
#define HM5883L_DATA_Z_H 0x05
#define HM5883L_DATA_Z_L 0x06
#define HM5883L_DATA_Y_H 0x07
#define HM5883L_DATA_Y_L 0x08
#define HM5883L_STATUS 0x09
#define HM5883L_IDENTIFICATION_A 0x10
#define HM5883L_IDENTIFICATION_B 0x11
#define HM5883L_IDENTIFICATION_C 0x12
//****************************************************************//
//mpu6050 register define
#define SENSOR_MPU6050 SENSOR_HM5883L+1
#define MPU6050_SLAVE_ADDRESS 0xD0
#define SELF_TEST_X 0x0D
#define SELF_TEST_Y 0x0E
#define SELF_TEST_Z 0x0F
#define SELF_TEST_A 0x10
#define SMPLRT_DIV 0x19
#define CONFIG 0x1A
#define GYRO_CONFIG 0x1B
#define ACCEL_CONFIG 0x1C
#define MOT_THR 0x1F
#define FIFO_EN 0x23
#define I2C_MST_CTRL 0x24
#define I2C_SLV0_ADDR 0x25
#define I2C_SLV0_REG 0x26
#define I2C_SLV0_CTRL 0x27
#define I2C_SLV0_DO 0x63
#define I2C_SLV1_ADDR 0x28
#define I2C_SLV1_REG 0x29
#define I2C_SLV1_CTRL 0x2A
#define I2C_SLV1_DO 0x64
#define I2C_SLV2_ADDR 0x2B
#define I2C_SLV2_REG 0x2C
#define I2C_SLV2_CTRL 0x2D
#define I2C_SLV2_DO 0x65
#define I2C_SLV3_ADDR 0x2E
#define I2C_SLV3_REG 0x2F
#define I2C_SLV3_CTRL 0x30
#define I2C_SLV3_DO 0x66
#define I2C_SLV4_ADDR 0x31
#define I2C_SLV4_REG 0x32
#define I2C_SLV4_DO 0x33
#define I2C_SLV4_CTRL 0x34
#define I2C_SLV4_DI 0x35
#define I2C_MST_STATUS 0x36
#define INT_PIN_CFG 0x37
#define INT_ENABLE 0x38
#define INT_STATUS 0x3A
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
#define EXT_SENS_DATA_00 0x49
//........
#define EXT_SENS_DATA_23 0x60
#define I2C_MST_DELAY_CTRL 0x67
#define SIGNAL_PATH_RESET 0x68
#define MOT_DETECT_CTRL 0x69
#define USER_CTRL 0x6A
#define PWR_MGMT_1 0x6B
#define PWR_MGMT_2 0x6C
#define FIFO_COUNTH 0x72
#define FIFO_COUNTL 0x73
#define FIFO_R_W 0x74
#define WHO_AM_I 0x75
//****************************************************************//
#define SALVE_ADDRESS(type) (type==SENSOR_HM5883L?HM5883L_SLAVE_ADDRESS:MPU6050_SLAVE_ADDRESS)
#define SCL 1
#define SDA 9
#define uchar unsigned char
int sensor_data[10];
//****************************************************************//
struct sensor_ok6410_dev{
struct cdev cdev_sensor;
struct class *sensor_class;
dev_t devno;
atomic_t counter[5];
//GPP Timer
struct timer_list gpp_timer[5];
};
/**
*传感器配置参数
*
* **/
typedef struct sensor_config{
unsigned char mpu6050_pwr_mgmt_1;
unsigned char mpu6050_smplrt_div;
unsigned char mpu6050_config;
unsigned char mpu6050_gyro_config;
unsigned char mpu6050_accel_config;
unsigned char mpu6050_int_pin_cfg;
unsigned char mpu6050_user_ctrl;
unsigned char hm5883l_mode;
}Sensor_Config;
//****************************************************************//
struct sensor_ok6410_dev *p_sensor_dev=NULL;
static void gpp_timer_ini_handler(unsigned long arg);
static void I2C_SendACK(int ack);
static char I2C_RecvByte(void);
static void Single_WriteI2C(int type,char REG_Address, char REG_data);
static void InitMPU6050_HM5883L(void);
static void I2C_RecvACK(void);
static void I2C_Start_Stop(int key) {
s3c_gpio_cfgpin(S3C64XX_GPP(SCL), S3C_GPIO_SFN(1));//out
s3c_gpio_cfgpin(S3C64XX_GPP(SDA), S3C_GPIO_SFN(1));//out
if(key==1){
gpio_set_value(S3C64XX_GPP(SCL), 1);
gpio_set_value(S3C64XX_GPP(SDA), 1);
udelay(5);
gpio_set_value(S3C64XX_GPP(SDA), 0);
udelay(5);
gpio_set_value(S3C64XX_GPP(SCL), 0);
}
else
{
gpio_set_value(S3C64XX_GPP(SCL), 1);
gpio_set_value(S3C64XX_GPP(SDA), 0);
udelay(5);
gpio_set_value(S3C64XX_GPP(SDA), 1);
udelay(5);
}
s3c_gpio_cfgpin(S3C64XX_GPP(SCL), S3C_GPIO_SFN(1));
s3c_gpio_cfgpin(S3C64XX_GPP(SDA), S3C_GPIO_SFN(1));
}
static void I2C_SendACK(int ack) {
s3c_gpio_cfgpin(S3C64XX_GPP(SCL), S3C_GPIO_SFN(1));
s3c_gpio_cfgpin(S3C64XX_GPP(SDA), S3C_GPIO_SFN(1));
gpio_set_value(S3C64XX_GPP(SDA), ack);
gpio_set_value(S3C64XX_GPP(SCL), 1);
udelay(5);
gpio_set_value(S3C64XX_GPP(SCL), 0);
udelay(5);
s3c_gpio_cfgpin(S3C64XX_GPP(SCL), S3C_GPIO_SFN(1));
s3c_gpio_cfgpin(S3C64XX_GPP(SDA), S3C_GPIO_SFN(1));
}
static void I2C_RecvACK(){
int ack;
s3c_gpio_cfgpin(S3C64XX_GPP(SCL), S3C_GPIO_SFN(1));
s3c_gpio_cfgpin(S3C64XX_GPP(SDA), S3C_GPIO_SFN(1));
gpio_set_value(S3C64XX_GPP(SCL), 1);
udelay(5);
s3c_gpio_cfgpin(S3C64XX_GPP(SDA), S3C_GPIO_SFN(0));
ack=gpio_get_value(S3C64XX_GPP(SDA));
gpio_set_value(S3C64XX_GPP(SCL), 0);
udelay(5);
s3c_gpio_cfgpin(S3C64XX_GPP(SCL), S3C_GPIO_SFN(1));
s3c_gpio_cfgpin(S3C64XX_GPP(SDA), S3C_GPIO_SFN(1));
}
static void I2C_SendByte(char dat) {
char i;
s3c_gpio_cfgpin(S3C64XX_GPP(SCL), S3C_GPIO_SFN(1));//out
s3c_gpio_cfgpin(S3C64XX_GPP(SDA), S3C_GPIO_SFN(1));//out
for (i = 0; i < 8; i++)
{
gpio_set_value(S3C64XX_GPP(SDA), dat&0x80);
gpio_set_value(S3C64XX_GPP(SCL), 1);
udelay(5);
gpio_set_value(S3C64XX_GPP(SCL), 0);
udelay(5);
dat <<= 1;
}
s3c_gpio_cfgpin(S3C64XX_GPP(SCL), S3C_GPIO_SFN(1));
s3c_gpio_cfgpin(S3C64XX_GPP(SDA), S3C_GPIO_SFN(1));
I2C_RecvACK();
}
static char I2C_RecvByte(void) {
char i,dat = 0;
s3c_gpio_cfgpin(S3C64XX_GPP(SCL), S3C_GPIO_SFN(1));
s3c_gpio_cfgpin(S3C64XX_GPP(SDA), S3C_GPIO_SFN(1));
gpio_set_value(S3C64XX_GPP(SDA), 1);
s3c_gpio_cfgpin(S3C64XX_GPP(SDA), S3C_GPIO_SFN(0));
for (i = 0; i < 8; i++)
{
dat <<=1;
gpio_set_value(S3C64XX_GPP(SCL), 1);
udelay(5);
dat |=gpio_get_value(S3C64XX_GPP(SDA));
gpio_set_value(S3C64XX_GPP(SCL), 0);
udelay(5);
}
s3c_gpio_cfgpin(S3C64XX_GPP(SCL), S3C_GPIO_SFN(0));
s3c_gpio_cfgpin(S3C64XX_GPP(SDA), S3C_GPIO_SFN(0));
return dat;
}
/**
*Single Byte Write
* M |S AD+W RA DATA P
* S | ACK ACK ACK
***/
static void Single_WriteI2C(int type,char REG_Address, char REG_data) {
I2C_Start_Stop(1); //S
I2C_SendByte((char)SALVE_ADDRESS(type)); //AD+W
I2C_SendByte(REG_Address); //RA
I2C_SendByte(REG_data); //DATA
I2C_Start_Stop(0); //P
}
/**
*Continous Byte Write
* M |S AD+W RA DATA DATA P
* S | ACK ACK ACK ACK
***/
static void Continous_WriteI2C(int type,char REG_Address, char REG_data[2]) {
I2C_Start_Stop(1); //S
I2C_SendByte((char)SALVE_ADDRESS(type)); //AD+W
I2C_SendByte(REG_Address); //RA
I2C_SendByte(REG_data[1]); //DATA1
I2C_SendByte(REG_data[0]); //DATA0
I2C_Start_Stop(0); //P
}
/**
*Single Byte Read
* M |S AD+W RA S AD+R NACK P
* S | ACK ACK ACK DATA
***/
static signed char Single_ReadI2C(int type,char REG_Address) {
signed char REG_data;
I2C_Start_Stop(1); //S
I2C_SendByte((char)SALVE_ADDRESS(type) + 0); //AD+W
I2C_SendByte(REG_Address); //RA
I2C_Start_Stop(1); //S
I2C_SendByte((char)SALVE_ADDRESS(type) + 1); //AD+R
REG_data = I2C_RecvByte();//DATA
I2C_SendACK(0); //NACK
I2C_Start_Stop(0); //P
return REG_data;
}
/**
*Continous Byte Read
* M |S AD+W RA S AD+R ACK NACK P
* S | ACK ACK ACK DATA DATA
***/
static char* Continous_ReadI2C(int type,char REG_Address) {
char REG_data[2];
I2C_Start_Stop(1); //S
I2C_SendByte((char)SALVE_ADDRESS(type) + 0); //AD+W
I2C_SendByte(REG_Address); //RA
I2C_Start_Stop(1); //S
I2C_SendByte((char)SALVE_ADDRESS(type) + 1); //AD+R
REG_data[0] = I2C_RecvByte();//DATA H
I2C_SendACK(1); //ACK
REG_data[1] = I2C_RecvByte();//DATA L
I2C_SendACK(0); //NACK
I2C_Start_Stop(0); //P
return (char*)REG_data;
}
static void InitMPU6050_HM5883L(void) {
Single_WriteI2C(SENSOR_MPU6050,PWR_MGMT_1, 0x00);
Single_WriteI2C(SENSOR_MPU6050,SMPLRT_DIV, 0x07);
Single_WriteI2C(SENSOR_MPU6050,CONFIG, 0x06);
Single_WriteI2C(SENSOR_MPU6050,GYRO_CONFIG, 0x18);
Single_WriteI2C(SENSOR_MPU6050,ACCEL_CONFIG, 0x00);
Single_WriteI2C(SENSOR_MPU6050,INT_PIN_CFG,1<<1);
Single_WriteI2C(SENSOR_MPU6050,USER_CTRL,0<<5);
//open hm5883l
Single_WriteI2C(SENSOR_HM5883L,HM5883L_MODE,0x00);
}
static void GetSensorData(int type,char REG_Address,int *result) {
signed char H;
unsigned char L;
H = Single_ReadI2C(type,REG_Address);
L = Single_ReadI2C(type,REG_Address + 1);
*result =(int)((H << 8)|L);
}
static ssize_t s3c6410_sensor_read(struct file *filp, int __user *buf, ssize_t len)
{
int i=0;
int *pbuf=buf;
InitMPU6050_HM5883L();
//mpu6050
GetSensorData(SENSOR_MPU6050,ACCEL_XOUT_H , &sensor_data[0]);
GetSensorData(SENSOR_MPU6050,ACCEL_YOUT_H , &sensor_data[1]);
GetSensorData(SENSOR_MPU6050,ACCEL_ZOUT_H ,&sensor_data[2]);
GetSensorData(SENSOR_MPU6050,GYRO_XOUT_H , &sensor_data[3]);
GetSensorData(SENSOR_MPU6050,GYRO_YOUT_H , &sensor_data[4]);
GetSensorData(SENSOR_MPU6050,GYRO_ZOUT_H , &sensor_data[5]);
//mpu6050
GetSensorData(SENSOR_MPU6050,TEMP_OUT_H , &sensor_data[6]);
//hm5883l
GetSensorData(SENSOR_HM5883L,HM5883L_DATA_X_H,&sensor_data[7]);
GetSensorData(SENSOR_HM5883L,HM5883L_DATA_Y_H,&sensor_data[8]);
GetSensorData(SENSOR_HM5883L,HM5883L_DATA_Z_H,&sensor_data[9]);
if(false){
printk(KERN_EMERG "Acc: %d %d %d Gyro: %d %d %d Compass: : %d %d %d\n",
sensor_data[0],sensor_data[1],sensor_data[2],
sensor_data[3],sensor_data[4],sensor_data[5],
sensor_data[6],sensor_data[7],sensor_data[8]);
}
for(i=0;i<sizeof(sensor_data)/sizeof(sensor_data[0]);i++){
copy_to_user(pbuf+i,&sensor_data[i],sizeof(sensor_data[i]));
}
return (ssize_t)sizeof(sensor_data);
}
static DEFINE_TIMER(gpp_timer1, gpp_timer_ini_handler, 20, 0);
static DEFINE_TIMER(gpp_timer8, gpp_timer_ini_handler, 20, 0);
static DEFINE_TIMER(gpp_timer9, gpp_timer_ini_handler, 20, 0);
static DEFINE_TIMER(gpp_timer12, gpp_timer_ini_handler, 20, 0);
static DEFINE_TIMER(gpp_timer13, gpp_timer_ini_handler, 20, 0);
/*定时器处理函数*/
static void gpp_timer_ini_handler(unsigned long arg)
{
mod_timer(&p_sensor_dev->gpp_timer[arg],jiffies + HZ);
atomic_inc(&p_sensor_dev->counter[arg]);
}
/*设备打开函数*/
static int s3c6410_sensor_open(
struct inode *inode,
struct file *file)
{
/*初始化定时器*/
int i=0;
for(i=0;i<5;i++){
init_timer(&p_sensor_dev->gpp_timer[i]);
p_sensor_dev->gpp_timer[i].function = &gpp_timer_ini_handler;
p_sensor_dev->gpp_timer[i].expires = jiffies + HZ;
p_sensor_dev->gpp_timer[i].data=(unsigned long)i;
add_timer(&p_sensor_dev->gpp_timer[i]);
atomic_set(&p_sensor_dev->counter[i],0);//计数0
}
//sensor initial
InitMPU6050_HM5883L();
return 0;
}
/*设备释放函数*/
static int s3c6410_sensor_release(
struct inode *inode,
struct file *file)
{
int i=0;
for(i=0;i<5;i++){
del_timer(&p_sensor_dev->gpp_timer[i]);
}
return 0;
}
/**
* arg:0~2000
* */
static int s3c6410_sensor_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg) {
switch (cmd) {
case -1:
case 0:
return 0;
default:
return -EINVAL;
}
}
static struct file_operations s3c6410_sensor_fops = {
.owner = THIS_MODULE,
.open = s3c6410_sensor_open,
.release = s3c6410_sensor_release,
.ioctl = s3c6410_sensor_ioctl,
.read = s3c6410_sensor_read,
};
/*设备初始化*/
static int __init s3c6410_sensor_init(void)
{
unsigned long tmp;
int ret=0;
p_sensor_dev = (struct sensor_ok6410_dev *)kmalloc(sizeof(struct sensor_ok6410_dev),GFP_KERNEL);
if(!p_sensor_dev)
{
ret=- ENOMEM;
goto fail_malloc;
}
if(alloc_chrdev_region(&p_sensor_dev->devno, 0,1, DEVICE_NAME)<0)
{
return ret;
}
cdev_init(&p_sensor_dev->cdev_sensor,&s3c6410_sensor_fops);
p_sensor_dev->cdev_sensor.owner = THIS_MODULE;
ret =cdev_add(&p_sensor_dev->cdev_sensor,p_sensor_dev->devno,1);
if(ret)
{
return ret;
}
p_sensor_dev->sensor_class = class_create(THIS_MODULE,DEVICE_NAME);
if(IS_ERR(p_sensor_dev->sensor_class))
{
return -1;
}
device_create(p_sensor_dev->sensor_class,NULL,MKDEV(MAJOR(p_sensor_dev->devno),0),NULL,DEVICE_NAME);
//gpm0-3 pull up
tmp = __raw_readl(S3C64XX_GPMPUD);
tmp &= (~0xFF);
tmp |= 0xaa; // 10101010
__raw_writel(tmp,S3C64XX_GPMPUD);
//gpm0-3 output mode
tmp = __raw_readl(S3C64XX_GPMCON);
tmp &= (~0xFFFF);
tmp |= 0x1111;
__raw_writel(tmp,S3C64XX_GPMCON);
//gpm0-3 output 0
tmp = __raw_readl(S3C64XX_GPMDAT);
tmp |= 0x10;
__raw_writel(tmp,S3C64XX_GPMDAT);
//*****************************************************//
gpp-1-8-9-12-13 pull up
tmp = __raw_readl(S3C64XX_GPPPUD);
tmp &= (~0xFFFF);
tmp |= 0xaaaaaaaa; //0000 1010 0000 1010 , 0000 0000 0000 1000 pull down
__raw_writel(tmp,S3C64XX_GPPPUD);
//gpp-1-8-9-12-13 output mode
tmp = __raw_readl(S3C64XX_GPPCON);
tmp &= (~0xFFFF);
tmp |= 0x05050004; // 0000 0101 0000 0101 , 0000 0000 0000 0100 output mode
__raw_writel(tmp,S3C64XX_GPPCON);
//gpp-1-8-9-12-13 output 0
tmp = __raw_readl(S3C64XX_GPPDAT);
tmp &= (~0xFFFF);
__raw_writel(tmp,S3C64XX_GPPDAT);
//*****************************************************//
return 0;
fail_malloc: unregister_chrdev_region(p_sensor_dev->devno,1);
return -1;
}
static void __exit s3c6410_sensor_exit(void)
{
unregister_chrdev_region(MKDEV(SENSOR_MAJOR,0),1);
device_destroy(p_sensor_dev->sensor_class,MKDEV(MAJOR(p_sensor_dev->devno),0));
cdev_del(&p_sensor_dev->cdev_sensor);
class_destroy(p_sensor_dev->sensor_class);
kfree(p_sensor_dev);
return;
}
module_init( s3c6410_sensor_init);
module_exit( s3c6410_sensor_exit);
MODULE_AUTHOR("clare liu 2013/11/15");
MODULE_LICENSE("GPL");
MPU6050和HMC5883L的字符驱动程序
最新推荐文章于 2024-03-17 21:47:09 发布