och1970 磁力三轴传感器android驱动代码

1、Kconfig

#
# Makefile for och1970 sensors driver.
#
config SENSORS_OCH1970
	tristate "OCH1970 accelerometer sensor device with I2C bus"
	depends on I2C
	default n
	help
	  Say Y here if you have a OCH1970 device on the board and use I2C
	  communication, else say N.

	  To compile this driver as a module, choose M here.

2、Makefile

#
# Makefile for och1970 sensor driver.
#
ccflags-y += -Wno-unused-result
ccflags-y += -Wno-unused-function
obj-$(CONFIG_SENSORS_OCH1970) += och1970.o

#ccflags-y += -Wno-unused-result
#ccflags-y += -Wno-unused-function
#obj-m :=och1970.o
#LINUX_KERNEL_PATH :=/home/powersys/lxx/HSC_8541E_ALL_F1/idh.code/out/target/product/sl8541e_1h10/obj/KERNEL/
#CROSS_COMPILE_PATH :=/home/powersys/lxx/HSC_8541E_ALL_F1/idh.code/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-
#PWD :=$(shell pwd)  
#all:
#	make ARCH=arm64 -C $(LINUX_KERNEL_PATH) M=$(PWD) CROSS_COMPILE=$(CROSS_COMPILE_PATH) modules
#clean:
#	make ARCH=arm64 -C $(LINUX_KERNEL_PATH) M=$(PWD) clean

3、och1970.h

#ifndef _MSPCO1_H_
#define _MSPCO1_H_

#include <linux/ioctl.h>

#define OCH1970_I2C_NAME		"OCH1970"
#define OCH1970_INPUT_NAME     "magnetic"

#define bit7    (0x01<<7)
#define bit6    (0x01<<6)
#define bit5    (0x01<<5)
#define bit4    (0x01<<4)
#define bit3    (0x01<<3)
#define bit2    (0x01<<2)
#define bit1    (0x01<<1)
#define bit0    (0x01<<0)

#define OCH_DISABLE          0
#define OCH_ENABLE           1

//register address of the OCH1970
#define OCH1970_REG_WIA 0x00	   //company id & device id,4bytes
#define OCH1970_REG_STATUS1	0x10   //status data,2bytes
#define OCH1970_REG_DATAX 0x11	   //X data [15:0]
#define OCH1970_REG_DATAY 0x12     //Y data [15:0]
#define OCH1970_REG_DATAX_Y 0x13   //X data [15:0] & Y data [15:0]
#define OCH1970_REG_DATAZ 0x14
#define OCH1970_REG_DATAX_Z 0x15
#define OCH1970_REG_DATAY_Z 0x16
#define OCH1970_REG_DATAX_Y_Z 0x17

#define OCH1970_REG_STATUS2 0x18    //same with STATUS1
#define OCH1970_REG_DATAXH 0x19	    //X data [15:8] only 8bits
#define OCH1970_REG_DATAYH 0x1A     //Y data [15:8] only 8bits
#define OCH1970_REG_DATAXH_YH 0x1B  //X data [15:8] & Y data [15:8]
#define OCH1970_REG_DATAZH 0x1C
#define OCH1970_REG_DATAXH_ZH 0x1D
#define OCH1970_REG_DATAYH_ZH 0x1E
#define OCH1970_REG_DATAXH_YH_ZH 0x1F

#define OCH1970_REG_CNTL1 0X20      //CNTL1 config interrupt
#define OCH1970_REG_CNTL2 0x21      //CNTL2 config other things
#define OCH1970_REG_THRE_X1 0x22    //BOP&BRP setting
#define OCH1970_REG_THRE_X2 0x23
#define OCH1970_REG_THRE_Y1 0X24
#define OCH1970_REG_THRE_Y2 0X25
#define OCH1970_REG_THRE_Z1 0X26
#define OCH1970_REG_THRE_Z2 0X27

#define OCH1970_REG_SRST 0x30       //soft reset

//specific constant values
#define OCH1970_SLA 0x0D<<1 //8 bits address,if you use 7 bits address, the address is 0x0D;
#define OCH1970_VALUE_STANDBY_MODE 0x00
#define OCH1970_VALUE_SINGLE_MODE 0x01
#define OCH1970_VALUE_CONTINUOUS_MODE_1_0p5Hz 0x02
#define OCH1970_VALUE_CONTINUOUS_MODE_2_1Hz 0x04
#define OCH1970_VALUE_CONTINUOUS_MODE_3_2Hz 0x06
#define OCH1970_VALUE_CONTINUOUS_MODE_4_20Hz 0x08
#define OCH1970_VALUE_CONTINUOUS_MODE_5_40Hz 0x0A
#define OCH1970_VALUE_CONTINUOUS_MODE_6_100Hz 0x0C
#define OCH1970_VALUE_CONTINUOUS_MODE_7_500Hz 0x0E

#define LOG_TAG						"[OCH1970-Magnetic] "
#define OCH_INFO(fmt, args...)		printk(KERN_INFO LOG_TAG fmt, ##args)//KERN_INFO	KERN_EMERG
#define OCH_ERR(fmt, args...)		printk(KERN_ERR  LOG_TAG fmt, ##args)//KERN_ERR		KERN_EMERG

struct och1970_data {
	struct i2c_client *client;
	struct input_dev *input;
	struct mutex irq_mutex;
	struct wake_lock time_lock;
	struct delayed_work work;
	struct work_struct irq_work;
	uint16_t bop_x1;
	uint16_t brp_x1;
	uint16_t bop_y1;
	uint16_t brp_y1;
	uint16_t bop_z1;
	uint16_t brp_z1;
	int16_t x_data;
	int16_t y_data;
	int16_t z_data;
	bool wakeup;
	int delay;
	int enable;
	int irq_gpio;
	int rst_gpio;
	int irq_number;
};


#endif /* _OCH1970_H_ */


4、och1970.c

#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/sysctl.h>
#include <linux/regulator/consumer.h>
#include <linux/input.h>
#include <linux/regmap.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/input-polldev.h>
#include <linux/workqueue.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/wakelock.h>
#include <linux/hrtimer.h>
#include <linux/kthread.h>
#include <linux/sched/rt.h>
#include "och1970.h"

static struct och1970_data *t_och1970 = NULL;

static int och1970_i2c_read(uint8_t reg, uint8_t len, uint8_t *data)
{
	int err;

	err = i2c_smbus_read_i2c_block_data(t_och1970->client, reg, len, data);
	if (err < 0) {
		OCH_ERR("%s: i2c_smbus_read_i2c_block_data failed.", __func__);
		return err;
	}

	return 0;
}

static int och1970_i2c_write(uint8_t reg, uint8_t len, uint8_t *data)
{
	int err;

	err = i2c_smbus_write_i2c_block_data(t_och1970->client, reg, len, data);
	if (err < 0) {
		OCH_ERR("%s: i2c_smbus_read_i2c_block_data failed.", __func__);
		return err;
	}

	return 0;
}

static void och1970_chip_reset(void)
{
	if(gpio_is_valid(t_och1970->rst_gpio)){
		gpio_set_value(t_och1970->rst_gpio, 1);
		msleep(20);
		gpio_set_value(t_och1970->rst_gpio, 0);
		msleep(20);
		gpio_set_value(t_och1970->rst_gpio, 1);
		msleep(200);
	}
}

static int check_chip_id(struct och1970_data *och1970)
{
	uint8_t chip_id[2];

	och1970_chip_reset();

	och1970_i2c_read(OCH1970_REG_WIA, 2, chip_id);
	
	OCH_INFO("%s chip_id0: 0x%x chip_id1: 0x%x\n", __func__, chip_id[0], chip_id[1]);
	
	if ((chip_id[0] == 0x48)&&(chip_id[1] == 0xC0))
		return 0;
	else
		return -EIO;
}

void och1970_init(void)
{
	uint8_t data_temp,now_value;

	och1970_i2c_read(OCH1970_REG_CNTL2, 1, &now_value);
	data_temp = (now_value & 0xF0) | 0x00;
	och1970_i2c_write(OCH1970_REG_CNTL2, 1, &data_temp);
	data_temp |= OCH1970_VALUE_CONTINUOUS_MODE_7_500Hz;
	och1970_i2c_write(OCH1970_REG_CNTL2, 1, &data_temp);

	och1970_i2c_read(OCH1970_REG_CNTL2, 1, &now_value);
	data_temp = now_value & ~bit4;
	och1970_i2c_write(OCH1970_REG_CNTL2, 1, &data_temp);

	och1970_i2c_read(OCH1970_REG_CNTL2, 1, &now_value);
	data_temp = (now_value & ~bit5) | bit5;
	och1970_i2c_write(OCH1970_REG_CNTL2, 1, &data_temp);
}

static uint8_t och1970_check_drdy(void)
{
	uint8_t drdy_flag[2];

	och1970_i2c_read(OCH1970_REG_STATUS1, 2, drdy_flag);

	return ((drdy_flag[1] & bit0) == bit0);	
}

static void och1970_set_threshold_x1(uint8_t *value)
{
	t_och1970->bop_x1 = (uint16_t)(((value[0] << 8) & 0xff00) | (value[1] & 0xff));
	t_och1970->brp_x1 = (uint16_t)(((value[2] << 8) & 0xff00) | (value[3] & 0xff));
	och1970_i2c_write(OCH1970_REG_THRE_X1, 4, value);
}

static void och1970_set_threshold_y1(uint8_t *value)
{
	t_och1970->bop_y1 = (uint16_t)(((value[0] << 8) & 0xff00) | (value[1] & 0xff));
	t_och1970->brp_y1 = (uint16_t)(((value[2] << 8) & 0xff00) | (value[3] & 0xff));
	och1970_i2c_write(OCH1970_REG_THRE_Y1, 4, value);
}

static void och1970_set_threshold_z1(uint8_t *value)
{
	t_och1970->bop_z1 = (uint16_t)(((value[0] << 8) & 0xff00) | (value[1] & 0xff));
	t_och1970->brp_z1 = (uint16_t)(((value[2] << 8) & 0xff00) | (value[3] & 0xff));	
	och1970_i2c_write(OCH1970_REG_THRE_Z1, 4, value);
}

static void och1970_en_drdy(bool flage)
{
	uint8_t now_value[2];

	och1970_i2c_read(OCH1970_REG_CNTL1, 2, now_value);
	if(flage)
		now_value[1] = (now_value[1] & ~bit0) | bit0;
	else
		now_value[1] = now_value[1] & ~bit0;

	och1970_i2c_write(OCH1970_REG_CNTL1, 2, now_value);
}

static void och1970_en_swx1(bool flage)
{
	uint8_t now_value[2];

	och1970_i2c_read(OCH1970_REG_CNTL1, 2, now_value);
	if(flage)
		now_value[1] = (now_value[1] & ~bit1) | bit1;
	else
		now_value[1] = now_value[1] & ~bit1;

	och1970_i2c_write(OCH1970_REG_CNTL1, 2, now_value);
}

static void och1970_en_swy1(bool flage)
{
	uint8_t now_value[2];

	och1970_i2c_read(OCH1970_REG_CNTL1, 2, now_value);
	if(flage)
		now_value[1] = (now_value[1] & ~bit3) | bit3;
	else
		now_value[1] = now_value[1] & ~bit3;

	och1970_i2c_write(OCH1970_REG_CNTL1, 2, now_value);
}

static void och1970_en_swz1(bool flage)
{
	uint8_t now_value[2];

	och1970_i2c_read(OCH1970_REG_CNTL1, 2, now_value);
	if(flage)
		now_value[1] = (now_value[1] & ~bit5) | bit5;
	else
		now_value[1] = now_value[1] & ~bit5;

	och1970_i2c_write(OCH1970_REG_CNTL1, 2, now_value);
}

static void och1970_odinten(bool flage)
{
	uint8_t now_value[2];

	och1970_i2c_read(OCH1970_REG_CNTL1, 2, now_value);
	if(flage)
		now_value[0] = (now_value[0] & ~bit2) | bit2;
	else
		now_value[0] = now_value[0] & ~bit2;

	och1970_i2c_write(OCH1970_REG_CNTL1, 2, now_value);
}

static void och1970_get_x_data(void)
{
	uint8_t och1970_x_data_array[4] = {0};

	och1970_i2c_read(OCH1970_REG_DATAX, 4, och1970_x_data_array);
	t_och1970->x_data = (int16_t)(((uint16_t)och1970_x_data_array[2]<<8) | (uint16_t)och1970_x_data_array[3]);

}

static void och1970_get_y_data(void)
{
	uint8_t och1970_y_data_array[4] = {0};

	och1970_i2c_read(OCH1970_REG_DATAY, 4, och1970_y_data_array);
	t_och1970->y_data = (int16_t)(((uint16_t)och1970_y_data_array[2]<<8) | (uint16_t)och1970_y_data_array[3]);

}

static void och1970_get_z_data(void)
{
	uint8_t och1970_z_data_array[4] = {0};

	och1970_i2c_read(OCH1970_REG_DATAZ, 4, och1970_z_data_array);
	t_och1970->z_data = (int16_t)(((uint16_t)och1970_z_data_array[2]<<8) | (uint16_t)och1970_z_data_array[3]);
}

static void och1970_get_xy_data(void)
{
	uint8_t och1970_xy_data_array[6] = {0};

	och1970_i2c_read(OCH1970_REG_DATAX_Y, 6, och1970_xy_data_array);
	t_och1970->x_data = (int16_t)(((uint16_t)och1970_xy_data_array[4]<<8) | (uint16_t)och1970_xy_data_array[5]);
	t_och1970->y_data = (int16_t)(((uint16_t)och1970_xy_data_array[2]<<8) | (uint16_t)och1970_xy_data_array[3]);

}

static void och1970_get_xz_data(void)
{
	uint8_t och1970_xz_data_array[6] = {0};

	och1970_i2c_read(OCH1970_REG_DATAX_Z, 6, och1970_xz_data_array);
	t_och1970->x_data = (int16_t)(((uint16_t)och1970_xz_data_array[4]<<8) | (uint16_t)och1970_xz_data_array[5]);
	t_och1970->z_data = (int16_t)(((uint16_t)och1970_xz_data_array[2]<<8) | (uint16_t)och1970_xz_data_array[3]);

}

static void och1970_get_yz_data(void)
{
	uint8_t och1970_yz_data_array[6] = {0};

	och1970_i2c_read(OCH1970_REG_DATAY_Z, 6, och1970_yz_data_array);
	t_och1970->y_data = (int16_t)(((uint16_t)och1970_yz_data_array[4]<<8) | (uint16_t)och1970_yz_data_array[5]);
	t_och1970->z_data = (int16_t)(((uint16_t)och1970_yz_data_array[2]<<8) | (uint16_t)och1970_yz_data_array[3]);

}

static void och1970_get_xyz_data(void)
{
	uint8_t och1970_xyz_data_array[8] = {0};

	och1970_i2c_read(OCH1970_REG_DATAX_Y_Z, 8, och1970_xyz_data_array);
	t_och1970->x_data = (int16_t)(((uint16_t)och1970_xyz_data_array[6]<<8) | (uint16_t)och1970_xyz_data_array[7]);
	t_och1970->y_data = (int16_t)(((uint16_t)och1970_xyz_data_array[4]<<8) | (uint16_t)och1970_xyz_data_array[5]);
	t_och1970->z_data = (int16_t)(((uint16_t)och1970_xyz_data_array[2]<<8) | (uint16_t)och1970_xyz_data_array[3]);

}

static void och1970_work_func(struct work_struct *work)
{
	struct och1970_data *och1970 = container_of((struct delayed_work *)work, struct och1970_data, work);

	if(och1970_check_drdy()==1){	//data is ready
		och1970_get_xyz_data();
		input_report_rel(och1970->input, REL_X, och1970->x_data);
		input_report_rel(och1970->input, REL_Y, och1970->y_data); 
		input_report_rel(och1970->input, REL_Z, och1970->z_data);
		input_sync(och1970->input);
		OCH_INFO("%s start  ###############\n", __func__);
		OCH_INFO("Xdata: %d \n", och1970->x_data);
		OCH_INFO("Ydata: %d \n", och1970->y_data);
		OCH_INFO("Zdata: %d \n", och1970->z_data);
		OCH_INFO("%s end  #################\n", __func__);
	}

	schedule_delayed_work(&och1970->work, msecs_to_jiffies(och1970->delay));
}

static void och1970_irq_work_fun(struct work_struct *work)
{
	mutex_lock(&t_och1970->irq_mutex);

	och1970_get_xyz_data();
	if (device_may_wakeup(&t_och1970->client->dev)) {
		pm_relax(&t_och1970->client->dev);
	}
	OCH_INFO("%s start  @@@@@@@@@@@@@@@@@@@\n", __func__);
	OCH_INFO("Xdata: %d \n", t_och1970->x_data);
	OCH_INFO("Ydata: %d \n", t_och1970->y_data);
	OCH_INFO("Zdata: %d \n", t_och1970->z_data);
	OCH_INFO("%s end  @@@@@@@@@@@@@@@@@@@@\n", __func__);
	if((t_och1970->x_data < t_och1970->brp_x1) && (t_och1970->y_data < t_och1970->brp_y1)){
		if(t_och1970->z_data < 0){
			input_report_key(t_och1970->input, KEY_F2, 1);
			input_report_key(t_och1970->input, KEY_F2, 0);
		}else {
			input_report_key(t_och1970->input, KEY_F3, 1);
			input_report_key(t_och1970->input, KEY_F3, 0);
		}
	}else if((t_och1970->x_data < t_och1970->brp_x1) && (t_och1970->y_data > t_och1970->brp_y1 * 3)){//°Î³ö ·§ÖµËæthreshold±ä»¯
		//och1970_en_swy1(true);
		input_report_key(t_och1970->input, KEY_F8, 1);
		input_report_key(t_och1970->input, KEY_F8, 0);	
	}else if (t_och1970->x_data > t_och1970->bop_x1){
		//och1970_en_swy1(false);
		input_report_key(t_och1970->input, KEY_F7, 1);
		input_report_key(t_och1970->input, KEY_F7, 0);
	}
	
	input_sync(t_och1970->input);
	msleep(100);
	enable_irq(t_och1970->irq_number);

	mutex_unlock(&t_och1970->irq_mutex);

}

static irqreturn_t och1970_handle_fun(int irq, void *desc)
{
	disable_irq_nosync(irq);
	wake_lock_timeout(&t_och1970->time_lock,5*HZ);
	if (device_may_wakeup(&t_och1970->client->dev)) {
		pm_stay_awake(&t_och1970->client->dev);
	}

	schedule_work(&t_och1970->irq_work);

	return IRQ_HANDLED;
}

static ssize_t och1970_enable_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", t_och1970->enable);
}

static ssize_t och1970_enable_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned int enable = simple_strtoul(buf, NULL, 10);

	OCH_INFO("#######enable=%d\n", enable);
	if (enable == 1){
		device_init_wakeup(&t_och1970->client->dev, true);
		och1970_en_swx1(true);
	}else if(enable == 2){
		schedule_delayed_work(&t_och1970->work, msecs_to_jiffies(t_och1970->delay));
	}else if(enable == 3){
		och1970_en_swx1(true);
		schedule_delayed_work(&t_och1970->work, msecs_to_jiffies(t_och1970->delay));
	}else{
		device_init_wakeup(&t_och1970->client->dev, false);
		//och1970_en_swy1(false);
		och1970_en_swx1(false);
		cancel_delayed_work_sync(&t_och1970->work);
	}

	return count;
}

static ssize_t och1970_wakeup_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%s\n", t_och1970->wakeup ? "true" : "false");
}

static ssize_t och1970_wakeup_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned int wakeup = simple_strtoul(buf, NULL, 10);

	OCH_INFO("#######wakeup=%d\n", wakeup);
	if (wakeup == 1){
		t_och1970->wakeup = true;
	}else{
		t_och1970->wakeup = false;
	}
	device_init_wakeup(&t_och1970->client->dev, t_och1970->wakeup);

	return count;
}

static ssize_t show_chipinfo_value(struct device *dev,
		struct device_attribute *attr, char *buf){

		return sprintf(buf, "och1970");
}

static ssize_t och1970_thresholdx1_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	uint8_t threshold[4];

	och1970_i2c_read(OCH1970_REG_THRE_X1, 4, threshold);

	return sprintf(buf, "BOP:%d\nBRP:%d\n", (((uint16_t)threshold[0]<<8) | (uint16_t)threshold[1]), (((uint16_t)threshold[2]<<8) | (uint16_t)threshold[3]));
}

static ssize_t och1970_thresholdx1_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	int i, j;
	uint8_t threshold[4];
	uint8_t bop_buf[100] = {0};
	uint8_t brp_buf[100] = {0};
	unsigned int bop_data = 0;
	unsigned int brp_data = 0;

	for(i = 0; i<100; i++){
		if(buf[i] == '\n'){
			memcpy(brp_buf, buf + j + 1, i-j);
			brp_data = simple_strtoul(brp_buf, NULL, 10);
			OCH_INFO("%s brp_data:%d\n", __func__, brp_data);
			break;
		}
		if(buf[i] == ' '){
			j = i;
			memcpy(bop_buf, buf, i);
			bop_data = simple_strtoul(bop_buf, NULL, 10);
			OCH_INFO("%s bop_data:%d\n", __func__, bop_data);
		}
	}
	if((0 < bop_data) && (bop_data < 0xffff) && (0 < brp_data) && (brp_data < 0xffff)){
		threshold[0] = (uint8_t)((bop_data & 0xff00) >> 8);
		threshold[1] = (uint8_t)(bop_data & 0xff);
		threshold[2] = (uint8_t)((brp_data & 0xff00) >> 8);
		threshold[3] = (uint8_t)(brp_data & 0xff);
		och1970_set_threshold_x1(threshold);
	}

	return count;
}

static ssize_t och1970_thresholdy1_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	uint8_t threshold[4];

	och1970_i2c_read(OCH1970_REG_THRE_Y1, 4, threshold);

	return sprintf(buf, "BOP:%d\nBRP:%d\n", (((uint16_t)threshold[0]<<8) | (uint16_t)threshold[1]), (((uint16_t)threshold[2]<<8) | (uint16_t)threshold[3]));
}

static ssize_t och1970_thresholdy1_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	int i, j;
	uint8_t threshold[4];
	uint8_t bop_buf[100] = {0};
	uint8_t brp_buf[100] = {0};
	unsigned int bop_data = 0;
	unsigned int brp_data = 0;

	for(i = 0; i<100; i++){
		if(buf[i] == '\n'){
			memcpy(brp_buf, buf + j + 1, i-j);
			brp_data = simple_strtoul(brp_buf, NULL, 10);
			OCH_INFO("%s brp_data:%d\n", __func__, brp_data);
			break;
		}
		if(buf[i] == ' '){
			j = i;
			memcpy(bop_buf, buf, i);
			bop_data = simple_strtoul(bop_buf, NULL, 10);
			OCH_INFO("%s bop_data:%d\n", __func__, bop_data);
		}
	}
	if((0 < bop_data) && (bop_data < 0xffff) && (0 < brp_data) && (brp_data < 0xffff)){
		threshold[0] = (uint8_t)((bop_data & 0xff00) >> 8);
		threshold[1] = (uint8_t)(bop_data & 0xff);
		threshold[2] = (uint8_t)((brp_data & 0xff00) >> 8);
		threshold[3] = (uint8_t)(brp_data & 0xff);
		och1970_set_threshold_y1(threshold);
	}

	return count;
}

static ssize_t och1970_thresholdz1_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	uint8_t threshold[4];

	och1970_i2c_read(OCH1970_REG_THRE_Z1, 4, threshold);

	return sprintf(buf, "BOP:%d\nBRP:%d\n", (((uint16_t)threshold[0]<<8) | (uint16_t)threshold[1]), (((uint16_t)threshold[2]<<8) | (uint16_t)threshold[3]));
}

static ssize_t och1970_thresholdz1_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	int i, j;
	uint8_t threshold[4];
	uint8_t bop_buf[100] = {0};
	uint8_t brp_buf[100] = {0};
	unsigned int bop_data = 0;
	unsigned int brp_data = 0;

	for(i = 0; i<100; i++){
		if(buf[i] == '\n'){
			memcpy(brp_buf, buf + j + 1, i-j);
			brp_data = simple_strtoul(brp_buf, NULL, 10);
			OCH_INFO("%s brp_data:%d\n", __func__, brp_data);
			break;
		}
		if(buf[i] == ' '){
			j = i;
			memcpy(bop_buf, buf, i);
			bop_data = simple_strtoul(bop_buf, NULL, 10);
			OCH_INFO("%s bop_data:%d\n", __func__, bop_data);
		}
	}
	if((0 < bop_data) && (bop_data < 0xffff) && (0 < brp_data) && (brp_data < 0xffff)){
		threshold[0] = (uint8_t)((bop_data & 0xff00) >> 8);
		threshold[1] = (uint8_t)(bop_data & 0xff);
		threshold[2] = (uint8_t)((brp_data & 0xff00) >> 8);
		threshold[3] = (uint8_t)(brp_data & 0xff);
		och1970_set_threshold_z1(threshold);
	}

	return count;
}

static DEVICE_ATTR(enable,		0644, och1970_enable_show, och1970_enable_store);
static DEVICE_ATTR(wakeup,		0644, och1970_wakeup_show, och1970_wakeup_store);
static DEVICE_ATTR(chipinfo,	0644, show_chipinfo_value, NULL);
static DEVICE_ATTR(thresholdx1,	0644, och1970_thresholdx1_show, och1970_thresholdx1_store);
static DEVICE_ATTR(thresholdy1,	0644, och1970_thresholdy1_show, och1970_thresholdy1_store);
static DEVICE_ATTR(thresholdz1,	0644, och1970_thresholdz1_show, och1970_thresholdz1_store);

static struct attribute *och1970_attributes[] = {
	&dev_attr_enable.attr,
	&dev_attr_wakeup.attr,
	&dev_attr_chipinfo.attr,
	&dev_attr_thresholdx1.attr,
	&dev_attr_thresholdy1.attr,
	&dev_attr_thresholdz1.attr,
	NULL
};

static struct attribute_group och1970_attribute_grout = {
	.attrs = och1970_attributes
};


#ifdef CONFIG_OF
static int och1970_parse_dt(struct och1970_data *och1970)
{
	struct device_node *np = och1970->client->dev.of_node;
	int ret;

	och1970->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0);
	if(gpio_is_valid(och1970->irq_gpio)){
		ret = gpio_request(och1970->irq_gpio, "och1970-irq");
		gpio_direction_input(och1970->irq_gpio);
	}else{
		OCH_ERR("%s: irq-gpio not find !!!\n", __func__);
		return -1;
	}

	och1970->rst_gpio = of_get_named_gpio(np, "rst-gpio", 0);
	if(gpio_is_valid(och1970->rst_gpio)){
		ret = gpio_request(och1970->rst_gpio, "och1970-rst");
		gpio_direction_output(och1970->rst_gpio, 0);
	}else{
		OCH_ERR("%s: rst-gpio not find !!!\n", __func__);
		gpio_free(och1970->irq_gpio);
		return -1;
	}

	return 0;
}
#endif

static int och1970_input_init(struct och1970_data *och1970)
{
	struct input_dev *dev = NULL;
	int err = 0;

	OCH_INFO("%s start\n", __func__);
	dev = input_allocate_device();
	if (!dev) {
		OCH_ERR("%s: can't allocate device!\n", __func__);
		return -ENOMEM;
	}

	dev->name = OCH1970_INPUT_NAME;
	dev->id.bustype = BUS_I2C;
	dev->evbit[0] = BIT_MASK(EV_REL);
	dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) | BIT_MASK(REL_Z) | BIT_MASK(REL_MISC);
	__set_bit(KEY_F2, dev->keybit);
	__set_bit(KEY_F3, dev->keybit);
	__set_bit(KEY_F7, dev->keybit);
	__set_bit(KEY_F8, dev->keybit);
	set_bit(EV_KEY, dev->evbit);

	input_set_drvdata(dev, och1970);

	err = input_register_device(dev);	
	if (err < 0) {
		OCH_ERR("%s: can't register device!\n", __func__);
		input_free_device(dev);
		return err;
	}
	och1970->input = dev;

	OCH_INFO("%s successful\n", __func__);
	return 0;
}

static void och1970_input_deinit(struct och1970_data *och1970)
{
	struct input_dev *dev = och1970->input;

	OCH_INFO("%s \n", __func__);
	input_unregister_device(dev);	
	//input_free_device(dev);
}

static int och1970_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int err = 0;
	uint8_t threshold_x1[] = {0x11, 0x94, 0x11, 0x94};
	uint8_t threshold_y1[] = {0x02, 0x58, 0x02, 0x58};
	uint8_t threshold_z1[] = {0x05, 0x46, 0x05, 0x46};
	struct och1970_data *och1970 = NULL;

	OCH_INFO("%s start\n", __func__);

	/* check i2c function */
	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
		OCH_ERR("%s: i2c function not support!\n", __func__);
		err = -ENODEV;
		goto exit;
	}
	/* setup private data */
	och1970 = kzalloc(sizeof(struct och1970_data), GFP_KERNEL);
	if (!och1970) {
		OCH_ERR("%s: can't allocate memory for och1970_data!\n", __func__);
		err = -ENOMEM;
		goto exit;
	}
	t_och1970 = och1970;
	och1970->wakeup = true;
	och1970->client = client;

	i2c_set_clientdata(client, och1970);

#ifdef CONFIG_OF
	if(och1970->client->dev.of_node){
		if(och1970_parse_dt(och1970))
			goto exit;
	}
#endif

	mutex_init(&och1970->irq_mutex);
	
	if(check_chip_id(och1970)){
		OCH_ERR("%s: check chip id failed\n", __func__);
		goto exit1;
	}

	och1970_init();

	err = och1970_input_init(och1970);
	if (err < 0) {		
		OCH_ERR("input init fail!\n");
		goto exit1;
	}

	och1970->delay = 100;
	wake_lock_init(&och1970->time_lock, WAKE_LOCK_SUSPEND, "och1970-time");
	device_init_wakeup(&och1970->client->dev, och1970->wakeup);
	INIT_DELAYED_WORK(&och1970->work, och1970_work_func);
	INIT_WORK(&och1970->irq_work, och1970_irq_work_fun);
	och1970_set_threshold_x1(threshold_x1);
	och1970_set_threshold_y1(threshold_y1);
	och1970_set_threshold_z1(threshold_z1);
	och1970_en_swx1(false);
	och1970_en_swy1(true);
	och1970_en_swz1(false);
	och1970_odinten(true);
	och1970_en_drdy(false);
	if(gpio_is_valid(och1970->irq_gpio)){
		och1970->irq_number = gpio_to_irq(och1970->irq_gpio);
		err = request_irq(och1970->irq_number, och1970_handle_fun, IRQF_TRIGGER_LOW | IRQF_ONESHOT, "och1970-irq", NULL);
	}

	err = sysfs_create_group(&och1970->input->dev.kobj, &och1970_attribute_grout);
	if(err < 0){
		OCH_ERR("%s:input create group fail!\n", __func__);
		goto exit2;
	}

	OCH_INFO("%s successful\n", __func__);
	return 0;

exit2:
	free_irq(och1970->irq_number, NULL);
	och1970_input_deinit(och1970);
	cancel_work_sync(&och1970->irq_work);
exit1:
	mutex_destroy(&och1970->irq_mutex);
	gpio_free(och1970->irq_gpio);
	gpio_free(och1970->rst_gpio);
	kfree(och1970);
exit:
	return err;
}

static int och1970_i2c_remove(struct i2c_client *client)
{
	struct och1970_data *och1970 = i2c_get_clientdata(client);

	sysfs_remove_group(&och1970->input->dev.kobj, &och1970_attribute_grout);
	free_irq(och1970->irq_number, NULL);
	cancel_work_sync(&och1970->irq_work);
	och1970_input_deinit(och1970);
	mutex_destroy(&och1970->irq_mutex);
	gpio_free(och1970->irq_gpio);
	gpio_free(och1970->rst_gpio);
	kfree(och1970);

	return 0;
}

static int och1970_resume(struct device *dev)
{
	struct och1970_data *och1970 = i2c_get_clientdata(to_i2c_client(dev));

	if (device_may_wakeup(&och1970->client->dev)) {
		OCH_INFO("%s: %d\n", __FUNCTION__, __LINE__);
		enable_irq_wake(och1970->irq_number);
	}
	return 0;
}

static int och1970_suspend(struct device *dev)
{
	struct och1970_data *och1970 = i2c_get_clientdata(to_i2c_client(dev));

	if (device_may_wakeup(&och1970->client->dev)) {
		OCH_INFO("%s: %d\n", __FUNCTION__, __LINE__);
		enable_irq_wake(och1970->irq_number);
	}
	return 0;
}

static SIMPLE_DEV_PM_OPS(och1970_pm_ops, och1970_suspend, och1970_resume);
			 
static const struct i2c_device_id och1970_id[] = {
	{OCH1970_I2C_NAME, 0},
	{ }
};
MODULE_DEVICE_TABLE(i2c, och1970_id);

static const struct of_device_id och1970_acc_of_match[] = {
       { .compatible = "magnetic,och1970", },
       { }
};
MODULE_DEVICE_TABLE(of, och1970_acc_of_match);

static struct i2c_driver och1970_driver = {
	.driver = {
		.name = OCH1970_I2C_NAME,
		.owner = THIS_MODULE,
		.of_match_table = och1970_acc_of_match,
		.pm = &och1970_pm_ops,
	},
	.probe    = och1970_i2c_probe,
	.remove   = och1970_i2c_remove,
	.id_table = och1970_id,
};

static int __init och1970_i2c_init(void)
{
	OCH_INFO("%s magnetic driver: init\n", OCH1970_I2C_NAME);

	return i2c_add_driver(&och1970_driver);
}

static void __exit och1970_i2c_exit(void)
{
	OCH_INFO("%s magnetic driver exit\n", OCH1970_I2C_NAME);

	i2c_del_driver(&och1970_driver);
}

module_init(och1970_i2c_init);
module_exit(och1970_i2c_exit);

MODULE_DESCRIPTION("och1970 magnetic driver");
MODULE_AUTHOR("HSC LXX");
MODULE_LICENSE("GPL");

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值