Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e3ead819 authored by autobot's avatar autobot Committed by Oliver Wang
Browse files

first commit

Change-Id: I9cc6dd97615f646a620bf72abf5da4fdf6444ad0
Git-commit: 473ebcb7b039f3f71afcacc4474393a6fd3fb1bf
Git-repo: https://github.com/autobot84/memsic-mag-sensor


[mengmeng@codeaurora.org: cherry-picked from mirrored branch]
Signed-off-by: default avatarOliver Wang <mengmeng@codeaurora.org>
parent 480c7178
Loading
Loading
Loading
Loading
+369 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 MEMSIC, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */

#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#include <asm/uaccess.h>
#include <linux/module.h>

#include "mecs.h"

#define DEBUG			0

#define ECS_DATA_DEV_NAME	"ecompass_data"
#define ECS_CTRL_DEV_NAME	"ecompass_ctrl"

static int ecs_ctrl_open(struct inode *inode, struct file *file);
static int ecs_ctrl_release(struct inode *inode, struct file *file);
static int ecs_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg);

static DECLARE_WAIT_QUEUE_HEAD(open_wq);

static atomic_t	open_count;
static atomic_t	open_flag;
static atomic_t	reserve_open_flag;

static atomic_t	a_flag;
static atomic_t	m_flag;
static atomic_t	o_flag;

static short ecompass_delay = 0;


static struct input_dev *ecs_data_device;

static struct file_operations ecs_ctrl_fops = {
	.owner		= THIS_MODULE,
	.open		= ecs_ctrl_open,
	.release	= ecs_ctrl_release,
	.unlocked_ioctl		= ecs_ctrl_ioctl,
};

static struct miscdevice ecs_ctrl_device = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = ECS_CTRL_DEV_NAME,
	.fops = &ecs_ctrl_fops,
};

static int ecs_ctrl_open(struct inode *inode, struct file *file)
{
#if 1
	atomic_set(&reserve_open_flag, 1);
	atomic_set(&open_flag, 1);
	atomic_set(&open_count, 1);
	wake_up(&open_wq);

	return 0;
#else
	int ret = -1;

	if (atomic_cmpxchg(&open_count, 0, 1) == 0) {
		if (atomic_cmpxchg(&open_flag, 0, 1) == 0) {
			atomic_set(&reserve_open_flag, 1);
			wake_up(&open_wq);
			ret = 0;
		}
	}

	return ret;
#endif
}

static int ecs_ctrl_release(struct inode *inode, struct file *file)
{
	atomic_set(&reserve_open_flag, 0);
	atomic_set(&open_flag, 0);
	atomic_set(&open_count, 0);
	wake_up(&open_wq);

	return 0;
}

static long ecs_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	void __user *pa = (void __user *)arg;
	short flag;
	short delay;
	int parms[4];
	int ypr[12];

	switch (cmd) {
	case ECOMPASS_IOC_SET_MODE:
		break;
	case ECOMPASS_IOC_SET_DELAY:
		if (copy_from_user(&delay, pa, sizeof(delay)))
			return -EFAULT;
		ecompass_delay = delay;
		break;
	case ECOMPASS_IOC_GET_DELAY:
		delay = ecompass_delay;
		if (copy_to_user(pa, &delay, sizeof(delay)))
			return -EFAULT;
		break;

	case ECOMPASS_IOC_SET_AFLAG:
		if (copy_from_user(&flag, pa, sizeof(flag)))
			return -EFAULT;
		if (flag < 0 || flag > 1)
			return -EINVAL;
		atomic_set(&a_flag, flag);
		break;
	case ECOMPASS_IOC_GET_AFLAG:
		flag = atomic_read(&a_flag);
		if (copy_to_user(pa, &flag, sizeof(flag)))
			return -EFAULT;
		break;
	case ECOMPASS_IOC_SET_MFLAG:
		if (copy_from_user(&flag, pa, sizeof(flag)))
			return -EFAULT;
		if (flag < 0 || flag > 1)
			return -EINVAL;
		atomic_set(&m_flag, flag);
		break;
	case ECOMPASS_IOC_GET_MFLAG:
		flag = atomic_read(&m_flag);
		if (copy_to_user(pa, &flag, sizeof(flag)))
			return -EFAULT;
		break;
	case ECOMPASS_IOC_SET_OFLAG:
		if (copy_from_user(&flag, pa, sizeof(flag)))
			return -EFAULT;
		if (flag < 0 || flag > 1)
			return -EINVAL;
		atomic_set(&o_flag, flag);
		break;
	case ECOMPASS_IOC_GET_OFLAG:
		flag = atomic_read(&o_flag);
		if (copy_to_user(pa, &flag, sizeof(flag)))
			return -EFAULT;
		break;

	case ECOMPASS_IOC_SET_APARMS:
		if (copy_from_user(parms, pa, sizeof(parms)))
			return -EFAULT;
		/* acceleration x-axis */
		input_set_abs_params(ecs_data_device, ABS_X, 
			parms[0], parms[1], parms[2], parms[3]);
		/* acceleration y-axis */
		input_set_abs_params(ecs_data_device, ABS_Y, 
			parms[0], parms[1], parms[2], parms[3]);
		/* acceleration z-axis */
		input_set_abs_params(ecs_data_device, ABS_Z, 
			parms[0], parms[1], parms[2], parms[3]);
		break;
	case ECOMPASS_IOC_GET_APARMS:
		break;
	case ECOMPASS_IOC_SET_MPARMS:
		if (copy_from_user(parms, pa, sizeof(parms)))
			return -EFAULT;
		/* magnetic raw x-axis */
		input_set_abs_params(ecs_data_device, ABS_HAT0X, 
			parms[0], parms[1], parms[2], parms[3]);
		/* magnetic raw y-axis */
		input_set_abs_params(ecs_data_device, ABS_HAT0Y, 
			parms[0], parms[1], parms[2], parms[3]);
		/* magnetic raw z-axis */
		input_set_abs_params(ecs_data_device, ABS_BRAKE, 
			parms[0], parms[1], parms[2], parms[3]);
		break;
	case ECOMPASS_IOC_GET_MPARMS:
		break;
	case ECOMPASS_IOC_SET_OPARMS_YAW:
		if (copy_from_user(parms, pa, sizeof(parms)))
			return -EFAULT;
		/* orientation yaw */
		input_set_abs_params(ecs_data_device, ABS_RX, 
			parms[0], parms[1], parms[2], parms[3]);
		break;
	case ECOMPASS_IOC_GET_OPARMS_YAW:
		break;
	case ECOMPASS_IOC_SET_OPARMS_PITCH:
		if (copy_from_user(parms, pa, sizeof(parms)))
			return -EFAULT;
		/* orientation pitch */
		input_set_abs_params(ecs_data_device, ABS_RY, 
			parms[0], parms[1], parms[2], parms[3]);
		break;
	case ECOMPASS_IOC_GET_OPARMS_PITCH:
		break;
	case ECOMPASS_IOC_SET_OPARMS_ROLL:
		if (copy_from_user(parms, pa, sizeof(parms)))
			return -EFAULT;
		/* orientation roll */
		input_set_abs_params(ecs_data_device, ABS_RZ, 
			parms[0], parms[1], parms[2], parms[3]);
		break;
	case ECOMPASS_IOC_GET_OPARMS_ROLL:
		break;

	case ECOMPASS_IOC_SET_YPR:
		if (copy_from_user(ypr, pa, sizeof(ypr)))
			return -EFAULT;
		/* Report acceleration sensor information */
		if (atomic_read(&a_flag)) {
			input_report_abs(ecs_data_device, ABS_X, ypr[0]);
			input_report_abs(ecs_data_device, ABS_Y, ypr[1]);
			input_report_abs(ecs_data_device, ABS_Z, ypr[2]);
			input_report_abs(ecs_data_device, ABS_WHEEL, ypr[3]);
		}

		/* Report magnetic sensor information */
		if (atomic_read(&m_flag)) {
			input_report_abs(ecs_data_device, ABS_HAT0X, ypr[4]);
			input_report_abs(ecs_data_device, ABS_HAT0Y, ypr[5]);
			input_report_abs(ecs_data_device, ABS_BRAKE, ypr[6]);
			input_report_abs(ecs_data_device, ABS_GAS, ypr[7]);
		}

		/* Report orientation information */
		if (atomic_read(&o_flag)) {
			input_report_abs(ecs_data_device, ABS_RX, ypr[8]);
			input_report_abs(ecs_data_device, ABS_RY, ypr[9]);
			input_report_abs(ecs_data_device, ABS_RZ, ypr[10]);
			input_report_abs(ecs_data_device, ABS_RUDDER, ypr[11]);
		}

		input_sync(ecs_data_device);
		break;

	default:
		break;
	}

	return 0;
}

static ssize_t ecs_ctrl_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	ssize_t ret = 0;

	sprintf(buf, "ecompass_ctrl");
	ret = strlen(buf) + 1;

	return ret;
}

static DEVICE_ATTR(ecs_ctrl, S_IRUGO, ecs_ctrl_show, NULL);

static int __init ecompass_init(void)
{
	int res = 0;

	pr_info("ecompass driver: init\n");

	ecs_data_device = input_allocate_device();
	if (!ecs_data_device) {
		res = -ENOMEM;
		pr_err("%s: failed to allocate input device\n", __FUNCTION__);
		goto out;
	}

	set_bit(EV_ABS, ecs_data_device->evbit);

	/* 32768 == 1g, range -4g ~ +4g */
	/* acceleration x-axis */
	input_set_abs_params(ecs_data_device, ABS_X, 
		-32768*4, 32768*4, 0, 0);
	/* acceleration y-axis */
	input_set_abs_params(ecs_data_device, ABS_Y, 
		-32768*4, 32768*4, 0, 0);
	/* acceleration z-axis */
	input_set_abs_params(ecs_data_device, ABS_Z, 
		-32768*4, 32768*4, 0, 0);
	/* acceleration status, 0 ~ 3 */
	input_set_abs_params(ecs_data_device, ABS_WHEEL, 
		0, 100, 0, 0);

	/* 32768 == 1gauss, range -4gauss ~ +4gauss */
	/* magnetic raw x-axis */
	input_set_abs_params(ecs_data_device, ABS_HAT0X, 
		-32768*4, 32768*4, 0, 0);
	/* magnetic raw y-axis */
	input_set_abs_params(ecs_data_device, ABS_HAT0Y, 
		-32768*4, 32768*4, 0, 0);
	/* magnetic raw z-axis */
	input_set_abs_params(ecs_data_device, ABS_BRAKE, 
		-32768*4, 32768*4, 0, 0);
	/* magnetic raw status, 0 ~ 3 */
	input_set_abs_params(ecs_data_device, ABS_GAS, 
		0, 100, 0, 0);

	/* 65536 == 360degree */
	/* orientation yaw, 0 ~ 360 */
	input_set_abs_params(ecs_data_device, ABS_RX, 
		0, 65536, 0, 0);
	/* orientation pitch, -180 ~ 180 */
	input_set_abs_params(ecs_data_device, ABS_RY, 
		-65536/2, 65536/2, 0, 0);
	/* orientation roll, -90 ~ 90 */
	input_set_abs_params(ecs_data_device, ABS_RZ, 
		-65536/4, 65536/4, 0, 0);
	/* orientation status, 0 ~ 3 */
	input_set_abs_params(ecs_data_device, ABS_RUDDER, 
		0, 100, 0, 0);

	ecs_data_device->name = ECS_DATA_DEV_NAME;
	res = input_register_device(ecs_data_device);
	if (res) {
		pr_err("%s: unable to register input device: %s\n",
			__FUNCTION__, ecs_data_device->name);
		goto out_free_input;
	}

	res = misc_register(&ecs_ctrl_device);
	if (res) {
		pr_err("%s: ecs_ctrl_device register failed\n", __FUNCTION__);
		goto out_free_input;
	}
	res = device_create_file(ecs_ctrl_device.this_device, &dev_attr_ecs_ctrl);
	if (res) {
		pr_err("%s: device_create_file failed\n", __FUNCTION__);
		goto out_deregister_misc;
	}

	return 0;

out_deregister_misc:
	misc_deregister(&ecs_ctrl_device);
out_free_input:
	input_free_device(ecs_data_device);
out:
	return res;
}

static void __exit ecompass_exit(void)
{
	pr_info("ecompass driver: exit\n");
	device_remove_file(ecs_ctrl_device.this_device, &dev_attr_ecs_ctrl);
	misc_deregister(&ecs_ctrl_device);
	input_free_device(ecs_data_device);
}

module_init(ecompass_init);
module_exit(ecompass_exit);

MODULE_DESCRIPTION("MEMSIC eCompass Driver");
MODULE_LICENSE("GPL");
+59 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 MEMSIC, Inc.
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */

/*
 * Definitions for ECOMPASS magnetic sensor chip.
 */
#ifndef __ECOMPASS_H__
#define __ECOMPASS_H__

#include <linux/ioctl.h>

/* Use 'e' as magic number */
#define ECOMPASS_IOM			'e'

/* IOCTLs for ECOMPASS device */
#define ECOMPASS_IOC_SET_MODE		_IOW(ECOMPASS_IOM, 0x00, short)
#define ECOMPASS_IOC_SET_DELAY		_IOW(ECOMPASS_IOM, 0x01, short)
#define ECOMPASS_IOC_GET_DELAY		_IOR(ECOMPASS_IOM, 0x02, short)

#define ECOMPASS_IOC_SET_AFLAG		_IOW(ECOMPASS_IOM, 0x10, short)
#define ECOMPASS_IOC_GET_AFLAG		_IOR(ECOMPASS_IOM, 0x11, short)
#define ECOMPASS_IOC_SET_MFLAG		_IOW(ECOMPASS_IOM, 0x12, short)
#define ECOMPASS_IOC_GET_MFLAG		_IOR(ECOMPASS_IOM, 0x13, short)
#define ECOMPASS_IOC_SET_OFLAG		_IOW(ECOMPASS_IOM, 0x14, short)
#define ECOMPASS_IOC_GET_OFLAG		_IOR(ECOMPASS_IOM, 0x15, short)

#define ECOMPASS_IOC_SET_APARMS		_IOW(ECOMPASS_IOM, 0x20, int[4])
#define ECOMPASS_IOC_GET_APARMS		_IOR(ECOMPASS_IOM, 0x21, int[4])
#define ECOMPASS_IOC_SET_MPARMS		_IOW(ECOMPASS_IOM, 0x22, int[4])
#define ECOMPASS_IOC_GET_MPARMS		_IOR(ECOMPASS_IOM, 0x23, int[4])
#define ECOMPASS_IOC_SET_OPARMS_YAW	_IOW(ECOMPASS_IOM, 0x24, int[4])
#define ECOMPASS_IOC_GET_OPARMS_YAW	_IOR(ECOMPASS_IOM, 0x25, int[4])
#define ECOMPASS_IOC_SET_OPARMS_PITCH	_IOW(ECOMPASS_IOM, 0x26, int[4])
#define ECOMPASS_IOC_GET_OPARMS_PITCH	_IOR(ECOMPASS_IOM, 0x27, int[4])
#define ECOMPASS_IOC_SET_OPARMS_ROLL	_IOW(ECOMPASS_IOM, 0x28, int[4])
#define ECOMPASS_IOC_GET_OPARMS_ROLL	_IOR(ECOMPASS_IOM, 0x29, int[4])

#define ECOMPASS_IOC_SET_YPR		_IOW(ECOMPASS_IOM, 0x30, int[12])


#endif /* __ECOMPASS_H__ */
+628 −0

File added.

Preview size limit exceeded, changes collapsed.

+67 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 MEMSIC, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */

/*
 * Definitions for mmc3416x magnetic sensor chip.
 */
#ifndef __MMC3416X_H__
#define __MMC3416X_H__

#include <linux/ioctl.h>

#define MMC3416X_I2C_NAME		"mmc3416x"

#define MMC3416X_I2C_ADDR		0x30

#define MMC3416X_REG_CTRL		0x07
#define MMC3416X_REG_BITS		0x08
#define MMC3416X_REG_DATA		0x00
#define MMC3416X_REG_DS			0x06
#define MMC3416X_REG_PRODUCTID_0		0x10
#define MMC3416X_REG_PRODUCTID_1		0x20

#define MMC3416X_CTRL_TM			0x01
#define MMC3416X_CTRL_CM			0x02
#define MMC3416X_CTRL_50HZ		0x00
#define MMC3416X_CTRL_25HZ		0x04
#define MMC3416X_CTRL_12HZ		0x08
#define MMC3416X_CTRL_NOBOOST            0x10
#define MMC3416X_CTRL_SET  	        0x20
#define MMC3416X_CTRL_RESET              0x40
#define MMC3416X_CTRL_REFILL             0x80

#define MMC3416X_BITS_SLOW_16            0x00
#define MMC3416X_BITS_FAST_16            0x01
#define MMC3416X_BITS_14                 0x02
/* Use 'm' as magic number */
#define MMC3416X_IOM			'm'

/* IOCTLs for MMC3416X device */
#define MMC3416X_IOC_TM			_IO (MMC3416X_IOM, 0x00)
#define MMC3416X_IOC_SET			_IO (MMC3416X_IOM, 0x01)
#define MMC3416X_IOC_READ		_IOR(MMC3416X_IOM, 0x02, int[3])
#define MMC3416X_IOC_READXYZ		_IOR(MMC3416X_IOM, 0x03, int[3])
#define MMC3416X_IOC_RESET               _IO (MMC3416X_IOM, 0x04)
#define MMC3416X_IOC_NOBOOST             _IO (MMC3416X_IOM, 0x05)
#define MMC3416X_IOC_ID                  _IOR(MMC3416X_IOM, 0x06, short)
#define MMC3416X_IOC_DIAG                _IOR(MMC3416X_IOM, 0x14, int[1])


#endif /* __MMC3416X_H__ */