/drivers/misc/bma150_spi.c
C | 510 lines | 363 code | 79 blank | 68 comment | 51 complexity | 1ea273fa6268f298467f981c50154ae7 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, LGPL-2.0
- /* drivers/misc/bma150_spi.c - bma150 G-sensor driver
- *
- * Copyright (C) 2009 HTC Corporation.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
- #include <linux/i2c.h>
- #include <linux/slab.h>
- #include <linux/miscdevice.h>
- #include <asm/uaccess.h>
- #include <linux/delay.h>
- #include <linux/input.h>
- #include <linux/bma150.h>
- #include <asm/gpio.h>
- #include <linux/earlysuspend.h>
- #include <linux/platform_device.h>
- #include <mach/atmega_microp.h>
- #define MAGIC_RETURN_NO 77
- static void spi_bma150_init_callback(void);
- struct early_suspend bma_early_suspend;
- static struct mutex set_normal_mode_mutex;
- static int set_normal_mode_cnt;
- static struct microp_gs_callback gs_callback = {
- .gs_init = spi_bma150_init_callback
- };
- static struct bma150_platform_data *this_pdata;
- static struct mutex gsensor_RW_mutex;
- static int spi_microp_enable(uint8_t on)
- {
- int ret;
- ret = microp_spi_vote_enable(SPI_GSENSOR, on);
- if (ret < 0) {
- printk(KERN_ERR "%s: i2c_write_block fail\n", __func__);
- return ret;
- }
- return ret;
- }
- static int spi_gsensor_read(uint8_t *data)
- {
- int ret;
- mutex_lock(&gsensor_RW_mutex);
- ret = microp_i2c_write(MICROP_I2C_WCMD_GSENSOR_REG_DATA_REQ, data, 1);
- if (ret < 0) {
- printk(KERN_ERR "%s: i2c_write_block fail\n", __func__);
- return ret;
- }
- ret = microp_i2c_read(MICROP_I2C_RCMD_GSENSOR_REG_DATA, data, 2);
- if (ret < 0) {
- printk(KERN_ERR "%s: i2c_read_block fail\n", __func__);
- return ret;
- }
- mutex_unlock(&gsensor_RW_mutex);
- return ret;
- }
- static int spi_gsensor_write(uint8_t *data)
- {
- int ret;
- mutex_lock(&gsensor_RW_mutex);
- ret = microp_i2c_write(MICROP_I2C_WCMD_GSENSOR_REG, data, 2);
- if (ret < 0) {
- printk(KERN_ERR "%s: i2c_write_block fail\n", __func__);
- return ret;
- }
- mutex_unlock(&gsensor_RW_mutex);
- return ret;
- }
- static int spi_gsensor_init_hw(void)
- {
- char buffer[2];
- memset(buffer, 0x0, sizeof(buffer));
- buffer[0] = RANGE_BWIDTH_REG;
- if (spi_gsensor_read(buffer) < 0)
- return -EIO;
- buffer[1] = (buffer[1]&0xe0);
- buffer[0] = RANGE_BWIDTH_REG;
- if (spi_gsensor_write(buffer) < 0)
- return -EIO;
- buffer[0] = SMB150_CONF2_REG;
- if (spi_gsensor_read(buffer) < 0)
- return -EIO;
- buffer[1] = buffer[1]|1<<3;
- buffer[0] = SMB150_CONF2_REG;
- if (spi_gsensor_write(buffer) < 0)
- return -EIO;
- return 0;
- }
- /*
- static int spi_gsensor_read_version(void)
- {
- uint8_t buffer[2];
- int ret = -EIO;
- buffer[0] = VERSION_REG;
- buffer[1] = 1;
- ret = spi_gsensor_read(buffer);
- if (ret < 0) {
- printk(KERN_ERR "%s: get al_version fail(%d)\n", __func__, ret);
- return ret;
- }
- printk(KERN_INFO "%s: al_version: 0x%2.2X\n", __func__, buffer[0]);
- buffer[0] = CHIP_ID_REG;
- buffer[1] = 1;
- ret = spi_gsensor_read(buffer);
- if (ret < 0) {
- printk(KERN_ERR "%s: get chip_id fail(%d)\n", __func__, ret);
- return ret;
- }
- printk(KERN_INFO "%s: chip_id: 0x%2.2X\n", __func__, buffer[0]);
- return 0;
- }
- */
- static int spi_bma150_TransRBuff(short *rbuf)
- {
- int ret;
- unsigned char buffer[6];
- memset(buffer, 0, 6);
- mutex_lock(&gsensor_RW_mutex);
- buffer[0] = 1;
- ret = microp_i2c_write(MICROP_I2C_WCMD_GSENSOR_DATA_REQ, buffer, 1);
- if (ret < 0) {
- printk(KERN_ERR "%s: i2c_write_block fail\n", __func__);
- return ret;
- }
- if (this_pdata && this_pdata->microp_new_cmd &&
- this_pdata->microp_new_cmd == 1) {
- /*printk(KERN_DEBUG "%s: New MicroP command\n", __func__);*/
- ret = microp_i2c_read(MICROP_I2C_RCMD_GSENSOR_DATA, buffer, 6);
- rbuf[0] = buffer[0]<<2|buffer[1]>>6;
- if (rbuf[0]&0x200)
- rbuf[0] -= 1<<10;
- rbuf[1] = buffer[2]<<2|buffer[3]>>6;
- if (rbuf[1]&0x200)
- rbuf[1] -= 1<<10;
- rbuf[2] = buffer[4]<<2|buffer[5]>>6;
- if (rbuf[2]&0x200)
- rbuf[2] -= 1<<10;
- } else {
- /* For Passion with V01 ~ V05 Microp */
- /*printk(KERN_DEBUG "%s: Old MicroP command\n", __func__);*/
- ret = microp_i2c_read(MICROP_I2C_RCMD_GSENSOR_X_DATA,
- buffer, 2);
- if (ret < 0) {
- printk(KERN_ERR "%s: i2c_read_block fail\n", __func__);
- return ret;
- }
- rbuf[0] = buffer[0]<<2|buffer[1]>>6;
- if (rbuf[0]&0x200)
- rbuf[0] -= 1<<10;
- ret = microp_i2c_read(MICROP_I2C_RCMD_GSENSOR_Y_DATA,
- buffer, 2);
- if (ret < 0) {
- printk(KERN_ERR "%s: i2c_read_block fail\n", __func__);
- return ret;
- }
- rbuf[1] = buffer[0]<<2|buffer[1]>>6;
- if (rbuf[1]&0x200)
- rbuf[1] -= 1<<10;
- ret = microp_i2c_read(MICROP_I2C_RCMD_GSENSOR_Z_DATA,
- buffer, 2);
- if (ret < 0) {
- printk(KERN_ERR "%s: i2c_read_block fail\n", __func__);
- return ret;
- }
- rbuf[2] = buffer[0]<<2|buffer[1]>>6;
- if (rbuf[2]&0x200)
- rbuf[2] -= 1<<10;
- }
- /* printk("X=%d, Y=%d, Z=%d\n",rbuf[0],rbuf[1],rbuf[2]);*/
- /* printk(KERN_DEBUG "%s: 0x%2.2X 0x%2.2X 0x%2.2X \
- 0x%2.2X 0x%2.2X 0x%2.2X\n",
- __func__, buffer[0], buffer[1], buffer[2], \
- buffer[3], buffer[4], buffer[5]);*/
- mutex_unlock(&gsensor_RW_mutex);
- return 1;
- }
- static int __spi_bma150_set_mode(char mode)
- {
- char buffer[2];
- int ret;
- if (mode == BMA_MODE_NORMAL) {
- spi_microp_enable(1);
- printk(KERN_INFO "%s: BMA get into NORMAL mode!\n",
- __func__);
- }
- buffer[0] = SMB150_CTRL_REG;
- ret = spi_gsensor_read(buffer);
- if (ret < 0)
- return -1;
- buffer[1] = (buffer[1]&0xfe)|mode;
- buffer[0] = SMB150_CTRL_REG;
- ret = spi_gsensor_write(buffer);
- if (mode == BMA_MODE_SLEEP) {
- spi_microp_enable(0);
- printk(KERN_INFO "%s: BMA get into SLEEP mode!\n",
- __func__);
- }
- return ret;
- }
- static int spi_bma150_set_mode(char mode)
- {
- int ret;
- printk(KERN_DEBUG "%s: set_normal_mode_cnt = %d, mode = %d\n",
- __func__, set_normal_mode_cnt, mode);
- if (mode == BMA_MODE_NORMAL) {
- if (!set_normal_mode_cnt++) /* 0 -> 1 */
- ret = __spi_bma150_set_mode(BMA_MODE_NORMAL);
- else
- return -MAGIC_RETURN_NO;
- } else {
- if (!--set_normal_mode_cnt) /* 1 -> 0 */
- ret = __spi_bma150_set_mode(BMA_MODE_SLEEP);
- else
- return -MAGIC_RETURN_NO;
- }
- return ret;
- }
- static int spi_bma150_open(struct inode *inode, struct file *file)
- {
- set_normal_mode_cnt = 0;
- return nonseekable_open(inode, file);
- }
- static int spi_bma150_release(struct inode *inode, struct file *file)
- {
- return 0;
- }
- static int spi_bma150_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
- {
- void __user *argp = (void __user *)arg;
- char rwbuf[8];
- char *toRbuf;
- int ret = -1;
- short buf[8], temp;
- switch (cmd) {
- case BMA_IOCTL_READ:
- case BMA_IOCTL_WRITE:
- case BMA_IOCTL_SET_MODE:
- if (copy_from_user(&rwbuf, argp, sizeof(rwbuf)))
- return -EFAULT;
- break;
- case BMA_IOCTL_READ_ACCELERATION:
- if (copy_from_user(&buf, argp, sizeof(buf)))
- return -EFAULT;
- break;
- default:
- break;
- }
- switch (cmd) {
- case BMA_IOCTL_INIT:
- ret = spi_gsensor_init_hw();
- if (ret < 0)
- return ret;
- break;
- case BMA_IOCTL_READ:
- if (rwbuf[0] < 1)
- return -EINVAL;
- ret = spi_gsensor_read(&rwbuf[1]);
- if (ret < 0)
- return ret;
- break;
- case BMA_IOCTL_WRITE:
- if (rwbuf[0] < 2)
- return -EINVAL;
- ret = spi_gsensor_write(&rwbuf[1]);
- if (ret < 0)
- return ret;
- break;
- case BMA_IOCTL_READ_ACCELERATION:
- ret = spi_bma150_TransRBuff(&buf[0]);
- if (ret < 0)
- return ret;
- break;
- case BMA_IOCTL_SET_MODE:
- printk(KERN_INFO "%s: Set mode by ioctl!\n",
- __func__);
- mutex_lock(&set_normal_mode_mutex);
- spi_bma150_set_mode(rwbuf[0]);
- mutex_unlock(&set_normal_mode_mutex);
- break;
- case BMA_IOCTL_GET_INT:
- temp = 0;
- break;
- default:
- return -ENOTTY;
- }
- switch (cmd) {
- case BMA_IOCTL_READ:
- toRbuf = &rwbuf[1];
- if (copy_to_user(argp, toRbuf, sizeof(rwbuf)-1))
- return -EFAULT;
- break;
- case BMA_IOCTL_READ_ACCELERATION:
- if (copy_to_user(argp, &buf, sizeof(buf)))
- return -EFAULT;
- break;
- case BMA_IOCTL_GET_INT:
- if (copy_to_user(argp, &temp, sizeof(temp)))
- return -EFAULT;
- break;
- default:
- break;
- }
- return 0;
- }
- static struct file_operations spi_bma_fops = {
- .owner = THIS_MODULE,
- .open = spi_bma150_open,
- .release = spi_bma150_release,
- .ioctl = spi_bma150_ioctl,
- };
- static struct miscdevice spi_bma_device = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = BMA150_G_SENSOR_NAME,
- .fops = &spi_bma_fops,
- };
- static void bma150_early_suspend(struct early_suspend *handler)
- {
- int ret;
- mutex_lock(&set_normal_mode_mutex);
- ret = spi_bma150_set_mode(BMA_MODE_SLEEP);
- mutex_unlock(&set_normal_mode_mutex);
- printk(KERN_DEBUG
- "%s: spi_bma150_set_mode returned = %d!\n",
- __func__, ret);
- }
- static void bma150_early_resume(struct early_suspend *handler)
- {
- int ret;
- mutex_lock(&set_normal_mode_mutex);
- ret = spi_bma150_set_mode(BMA_MODE_NORMAL);
- mutex_unlock(&set_normal_mode_mutex);
- printk(KERN_DEBUG
- "%s: spi_bma150_set_mode returned = %d!\n",
- __func__, ret);
- }
- static void spi_bma150_init_callback(void)
- {
- int ret;
- ret = spi_microp_enable(1);
- if (ret)
- printk(KERN_ERR "%s: spi_microp_enable(1) fail!\n",
- __func__);
- mutex_lock(&set_normal_mode_mutex);
- ret = __spi_bma150_set_mode(BMA_MODE_SLEEP);
- mutex_unlock(&set_normal_mode_mutex);
- if (ret)
- printk(KERN_DEBUG
- "%s: __spi_bma150_set_mode(BMA_MODE_SLEEP) fail!\n",
- __func__);
- }
- static int spi_gsensor_initial(void)
- {
- int ret;
- /* ret = spi_microp_enable(1);
- if (ret < 0) {
- printk(KERN_ERR "%s: spi_microp_enable fail\n", __func__);
- return ret;
- }*/
- /* ret = spi_gsensor_read_version();
- if (ret < 0) {
- printk(KERN_ERR "%s: get version fail\n", __func__);
- return ret;
- }*/
- /* ret = microp_gsensor_init_hw(client);
- if (ret < 0) {
- printk(KERN_ERR "%s: init g-sensor fail\n", __func__);
- return ret;
- }
- */
- ret = misc_register(&spi_bma_device);
- if (ret < 0) {
- printk(KERN_ERR "%s: init misc_register fail\n", __func__);
- return ret;
- }
- mutex_init(&set_normal_mode_mutex);
- mutex_init(&gsensor_RW_mutex);
- set_normal_mode_cnt = 0;
- ret = microp_register_gs_callback(&gs_callback);
- printk(KERN_DEBUG "%s: ret = %d\n", __func__, ret);
- if (ret == 0)
- spi_bma150_init_callback();
- bma_early_suspend.suspend = bma150_early_suspend;
- bma_early_suspend.resume = bma150_early_resume;
- register_early_suspend(&bma_early_suspend);
- return 0;
- }
- static int spi_bma150_probe(struct platform_device *pdev)
- {
- printk(KERN_INFO "%s: G-sensor connect with microP: "
- "start initial\n", __func__);
- this_pdata = pdev->dev.platform_data;
- /*
- printk(KERN_DEBUG "%s: this_pdata->microp_new_cmd = %d\n",
- __func__, this_pdata->microp_new_cmd);
- */
- spi_gsensor_initial();
- return 0;
- }
- static int spi_bma150_remove(struct platform_device *pdev)
- {
- return 0;
- }
- static struct platform_driver spi_bma150_driver = {
- .probe = spi_bma150_probe,
- .remove = spi_bma150_remove,
- .driver = {
- .name = BMA150_G_SENSOR_NAME,
- .owner = THIS_MODULE,
- },
- };
- static int __init spi_bma150_init(void)
- {
- return platform_driver_register(&spi_bma150_driver);
- }
- static void __exit spi_bma150_exit(void)
- {
- platform_driver_unregister(&spi_bma150_driver);
- }
- module_init(spi_bma150_init);
- module_exit(spi_bma150_exit);
- MODULE_DESCRIPTION("BMA150 G-sensor driver");
- MODULE_LICENSE("GPL");