diff options
author | Tao Huang <huangtao@rock-chips.com> | 2018-11-03 13:10:57 +0800 |
---|---|---|
committer | Tao Huang <huangtao@rock-chips.com> | 2018-11-03 13:10:57 +0800 |
commit | 6debc070cc8d6139ae212e15e2cfb59776076fc9 (patch) | |
tree | 7dd3ac8f46638a0ae0f55b1de5644d0d933afff9 /drivers/misc | |
parent | 00d955673844c5859c29820a73b1cab964b20528 (diff) |
drivers/misc: remove unused akm8963 driver
Change-Id: I02f5827ae72ec307df363345a8971c2cd6bc8447
Signed-off-by: Tao Huang <huangtao@rock-chips.com>
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/akm8963.c | 1466 |
1 files changed, 0 insertions, 1466 deletions
diff --git a/drivers/misc/akm8963.c b/drivers/misc/akm8963.c deleted file mode 100644 index 3085e43b0c86..000000000000 --- a/drivers/misc/akm8963.c +++ /dev/null @@ -1,1466 +0,0 @@ -/* drivers/misc/akm8963.c - akm8963 compass driver - * - * Copyright (C) 2007-2008 HTC Corporation. - * Author: Hou-Kun Chen <houkun.chen@gmail.com> - * - * 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. - * - */ - -/*#define DEBUG*/ -/*#define VERBOSE_DEBUG*/ - -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/slab.h> -#include <linux/irq.h> -#include <linux/miscdevice.h> -#include <linux/gpio.h> -#include <linux/uaccess.h> -#include <linux/delay.h> -#include <linux/input.h> -#include <linux/workqueue.h> -#include <linux/freezer.h> -#include <linux/akm8963.h> - -#define AKM8963_DEBUG_IF 0 -#define AKM8963_DEBUG_DATA 0 - -#define AKM_ACCEL_ITEMS 3 -/* Wait timeout in millisecond */ -#define AKM8963_DRDY_TIMEOUT 100 - -struct akm8963_data { - struct i2c_client *i2c; - struct input_dev *input; - struct device *class_dev; - struct class *compass; - struct delayed_work work; - - wait_queue_head_t drdy_wq; - wait_queue_head_t open_wq; - - struct mutex sensor_mutex; - int8_t sense_data[SENSOR_DATA_SIZE]; - struct mutex accel_mutex; - int16_t accel_data[AKM_ACCEL_ITEMS]; - - struct mutex val_mutex; - uint32_t enable_flag; - int64_t delay[AKM_NUM_SENSORS]; - - atomic_t active; - atomic_t is_busy; - atomic_t drdy; - atomic_t suspend; - - char layout; - char outbit; - int irq; - int rstn; -}; - -static struct akm8963_data *s_akm; - - - -/***** I2C I/O function ***********************************************/ -static int akm8963_i2c_rxdata( - struct i2c_client *i2c, - unsigned char *rxData, - int length) -{ - struct i2c_msg msgs[] = { - { - .addr = i2c->addr, - .flags = 0, - .len = 1, - .buf = rxData, - .scl_rate = 200*1000, - }, - { - .addr = i2c->addr, - .flags = I2C_M_RD, - .len = length, - .buf = rxData, - .scl_rate = 200*1000, - }, }; - unsigned char addr = rxData[0]; - - if (i2c_transfer(i2c->adapter, msgs, 2) < 0) { - dev_err(&i2c->dev, "%s: transfer failed.", __func__); - return -EIO; - } - - dev_vdbg(&i2c->dev, "RxData: len=%02x, addr=%02x, data=%02x", - length, addr, rxData[0]); - return 0; -} - -static int akm8963_i2c_txdata( - struct i2c_client *i2c, - unsigned char *txData, - int length) -{ - struct i2c_msg msg[] = { - { - .addr = i2c->addr, - .flags = 0, - .len = length, - .buf = txData, - .scl_rate = 200*1000, - }, }; - - if (i2c_transfer(i2c->adapter, msg, 1) < 0) { - dev_err(&i2c->dev, "%s: transfer failed.", __func__); - return -EIO; - } - - dev_vdbg(&i2c->dev, "TxData: len=%02x, addr=%02x data=%02x", - length, txData[0], txData[1]); - return 0; -} - -static int akm8963_i2c_check_device( - struct i2c_client *client) -{ - unsigned char buffer[2]; - int err; - - /* Set measure mode */ - buffer[0] = AK8963_REG_WIA; - err = akm8963_i2c_rxdata(client, buffer, 1); - if (err < 0) { - dev_err(&client->dev, - "%s: Can not read WIA.", __func__); - return err; - } - /* Check read data */ - if (buffer[0] != 0x48) { - dev_err(&client->dev, - "%s: The device is not AK8963.", __func__); - return -ENXIO; - } - - //printk("========[%x] ,[%x]" , buffer[0],buffer[1]); - return err; -} - -/***** akm miscdevice functions *************************************/ -static int AKECS_Open(struct inode *inode, struct file *file); -static int AKECS_Release(struct inode *inode, struct file *file); -static long AKECS_ioctl(struct file *file, - unsigned int cmd, unsigned long arg); - -static struct file_operations AKECS_fops = { - .owner = THIS_MODULE, - .open = AKECS_Open, - .release = AKECS_Release, - .unlocked_ioctl = AKECS_ioctl, -}; - -static struct miscdevice akm8963_dev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "akm8963_dev", - .fops = &AKECS_fops, -}; - -static int AKECS_Set_CNTL1( - struct akm8963_data *akm, - unsigned char mode) -{ - unsigned char buffer[2]; - int err; - - /* Busy check */ - if (atomic_cmpxchg(&akm->is_busy, 0, 1) != 0) { - dev_err(&akm->i2c->dev, "%s: device is busy.", __func__); - return -EBUSY; - } - - /* Set flag */ - atomic_set(&akm->drdy, 0); - - /* Set measure mode */ - buffer[0] = AK8963_REG_CNTL1; - buffer[1] = mode; - err = akm8963_i2c_txdata(akm->i2c, buffer, 2); - if (err < 0) { - dev_err(&akm->i2c->dev, "%s: Can not set CNTL.", __func__); - atomic_set(&akm->is_busy, 0); - } else { - dev_dbg(&akm->i2c->dev, "Mode is set to (%d).", mode); - } - - return err; -} - -static int AKECS_Set_PowerDown( - struct akm8963_data *akm) -{ - unsigned char buffer[2]; - int err; - - /* Set measure mode */ - buffer[0] = AK8963_REG_CNTL1; - buffer[1] = AK8963_MODE_POWERDOWN; - err = akm8963_i2c_txdata(akm->i2c, buffer, 2); - if (err < 0) { - dev_err(&akm->i2c->dev, - "%s: Can not set to measurement mode.", __func__); - atomic_set(&akm->is_busy, 0); - } else { - dev_dbg(&akm->i2c->dev, "Powerdown mode is set."); - } - - /* Set to initial status. */ - atomic_set(&akm->is_busy, 0); - atomic_set(&akm->drdy, 0); - - return err; -} - -static int AKECS_Reset( - struct akm8963_data *akm, - int hard) -{ - unsigned char buffer[2]; - int err = 0; - - if (hard != 0) { - gpio_set_value(akm->rstn, 0); - udelay(5); - gpio_set_value(akm->rstn, 1); - } else { - /* Set measure mode */ - buffer[0] = AK8963_REG_CNTL2; - buffer[1] = 0x01; - err = akm8963_i2c_txdata(akm->i2c, buffer, 2); - if (err < 0) { - dev_err(&akm->i2c->dev, - "%s: Can not set SRST bit.", __func__); - } else { - dev_dbg(&akm->i2c->dev, "Soft reset is done."); - } - } - - /* Device will be accessible 100 us after */ - udelay(100); - - return err; -} - -static int AKECS_SetMode( - struct akm8963_data *akm, - unsigned char mode) -{ - int err; - - switch (mode & 0x0F) { - case AK8963_MODE_SNG_MEASURE: - case AK8963_MODE_SELF_TEST: - case AK8963_MODE_FUSE_ACCESS: - err = AKECS_Set_CNTL1(akm, mode); - if ((err >= 0) && (akm->irq == 0)) { - schedule_delayed_work( - &akm->work, - usecs_to_jiffies(AK8963_MEASUREMENT_TIME_US)); - } - break; - case AK8963_MODE_POWERDOWN: - err = AKECS_Set_PowerDown(akm); - break; - default: - dev_err(&akm->i2c->dev, - "%s: Unknown mode(%d).", __func__, mode); - return -EINVAL; - } - - /* wait at least 100us after changing mode */ - udelay(100); - - return err; -} - -/* This function will block a process until the latest measurement - * data is available. - */ -static int AKECS_GetData( - struct akm8963_data *akm, - char *rbuf, - int size) -{ - int err; - err = wait_event_interruptible_timeout( - akm->drdy_wq, - atomic_read(&akm->drdy), - AKM8963_DRDY_TIMEOUT); - - if (err < 0) { - dev_err(&akm->i2c->dev, - "%s: wait_event failed (%d).", __func__, err); - return -1; - } - if (!atomic_read(&akm->drdy)) { - dev_err(&akm->i2c->dev, - "%s: DRDY is not set.", __func__); - return -1; - } - - mutex_lock(&akm->sensor_mutex); - memcpy(rbuf, akm->sense_data, size); - atomic_set(&akm->drdy, 0); - mutex_unlock(&akm->sensor_mutex); - - return 0; -} - -static void AKECS_SetYPR( - struct akm8963_data *akm, - int *rbuf) -{ - uint32_t ready; - dev_vdbg(&akm->i2c->dev, "AKM8963 %s: flag =0x%X", __func__, - rbuf[0]); - dev_vdbg(&akm->input->dev, " Acceleration[LSB]: %6d,%6d,%6d stat=%d", - rbuf[1], rbuf[2], rbuf[3], rbuf[4]); - dev_vdbg(&akm->input->dev, " Geomagnetism[LSB]: %6d,%6d,%6d stat=%d", - rbuf[5], rbuf[6], rbuf[7], rbuf[8]); - dev_vdbg(&akm->input->dev, " Orientation[YPR] : %6d,%6d,%6d", - rbuf[9], rbuf[10], rbuf[11]); - - /* No events are reported */ - if (!rbuf[0]) { - dev_dbg(&akm->i2c->dev, "Don't waste a time."); - return; - } - - mutex_lock(&akm->val_mutex); - ready = (akm->enable_flag & (uint32_t)rbuf[0]); - mutex_unlock(&akm->val_mutex); - - /* Report acceleration sensor information */ - if (ready & ACC_DATA_READY) { - input_report_abs(akm->input, ABS_X, rbuf[1]); - input_report_abs(akm->input, ABS_Y, rbuf[2]); - input_report_abs(akm->input, ABS_Z, rbuf[3]); - input_report_abs(akm->input, ABS_THROTTLE, rbuf[4]); - } - /* Report magnetic vector information */ - if (ready & MAG_DATA_READY) { - input_report_abs(akm->input, ABS_RX, rbuf[5]); - input_report_abs(akm->input, ABS_RY, rbuf[6]); - input_report_abs(akm->input, ABS_RZ, rbuf[7]); - input_report_abs(akm->input, ABS_RUDDER, rbuf[8]); - } - /* Report orientation sensor information */ - if (ready & ORI_DATA_READY) { - input_report_abs(akm->input, ABS_HAT0X, rbuf[9]); - input_report_abs(akm->input, ABS_HAT0Y, rbuf[10]); - input_report_abs(akm->input, ABS_HAT1X, rbuf[11]); - input_report_abs(akm->input, ABS_HAT1Y, rbuf[4]); - } - - input_sync(akm->input); -} - -static int AKECS_GetOpenStatus( - struct akm8963_data *akm) -{ - return wait_event_interruptible( - akm->open_wq, (atomic_read(&akm->active) != 0)); -} - -static int AKECS_GetCloseStatus( - struct akm8963_data *akm) -{ - return wait_event_interruptible( - akm->open_wq, (atomic_read(&akm->active) <= 0)); -} - -static int AKECS_Open(struct inode *inode, struct file *file) -{ - file->private_data = s_akm; - return nonseekable_open(inode, file); -} - -static int AKECS_Release(struct inode *inode, struct file *file) -{ - return 0; -} - -static long -AKECS_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - void __user *argp = (void __user *)arg; - struct akm8963_data *akm = file->private_data; - - /* NOTE: In this function the size of "char" should be 1-byte. */ - char i2c_buf[RWBUF_SIZE]; /* for READ/WRITE */ - int8_t sensor_buf[SENSOR_DATA_SIZE];/* for GETDATA */ - int32_t ypr_buf[YPR_DATA_SIZE]; /* for SET_YPR */ - int16_t acc_buf[3]; /* for GET_ACCEL */ - int64_t delay[AKM_NUM_SENSORS]; /* for GET_DELAY */ - char mode; /* for SET_MODE*/ - char layout; /* for GET_LAYOUT */ - char outbit; /* for GET_OUTBIT */ - int status; /* for OPEN/CLOSE_STATUS */ - int ret = -1; /* Return value. */ - - switch (cmd) { - case ECS_IOCTL_READ: - case ECS_IOCTL_WRITE: - if (argp == NULL) { - dev_err(&akm->i2c->dev, "invalid argument."); - return -EINVAL; - } - if (copy_from_user(&i2c_buf, argp, sizeof(i2c_buf))) { - dev_err(&akm->i2c->dev, "copy_from_user failed."); - return -EFAULT; - } - break; - case ECS_IOCTL_SET_MODE: - if (argp == NULL) { - dev_err(&akm->i2c->dev, "invalid argument."); - return -EINVAL; - } - if (copy_from_user(&mode, argp, sizeof(mode))) { - dev_err(&akm->i2c->dev, "copy_from_user failed."); - return -EFAULT; - } - break; - case ECS_IOCTL_SET_YPR: - if (argp == NULL) { - dev_err(&akm->i2c->dev, "invalid argument."); - return -EINVAL; - } - if (copy_from_user(&ypr_buf, argp, sizeof(ypr_buf))) { - dev_err(&akm->i2c->dev, "copy_from_user failed."); - return -EFAULT; - } - case ECS_IOCTL_GETDATA: - case ECS_IOCTL_GET_OPEN_STATUS: - case ECS_IOCTL_GET_CLOSE_STATUS: - case ECS_IOCTL_GET_DELAY: - case ECS_IOCTL_GET_LAYOUT: - case ECS_IOCTL_GET_OUTBIT: - case ECS_IOCTL_GET_ACCEL: - /* Just check buffer pointer */ - if (argp == NULL) { - dev_err(&akm->i2c->dev, "invalid argument."); - return -EINVAL; - } - break; - break; - default: - break; - } - - switch (cmd) { - case ECS_IOCTL_READ: - dev_vdbg(&akm->i2c->dev, "IOCTL_READ called."); - if ((i2c_buf[0] < 1) || (i2c_buf[0] > (RWBUF_SIZE-1))) { - dev_err(&akm->i2c->dev, "invalid argument."); - return -EINVAL; - } - ret = akm8963_i2c_rxdata(akm->i2c, &i2c_buf[1], i2c_buf[0]); - if (ret < 0) - return ret; - break; - case ECS_IOCTL_WRITE: - dev_vdbg(&akm->i2c->dev, "IOCTL_WRITE called."); - if ((i2c_buf[0] < 2) || (i2c_buf[0] > (RWBUF_SIZE-1))) { - dev_err(&akm->i2c->dev, "invalid argument."); - return -EINVAL; - } - ret = akm8963_i2c_txdata(akm->i2c, &i2c_buf[1], i2c_buf[0]); - if (ret < 0) - return ret; - break; - case ECS_IOCTL_SET_MODE: - dev_vdbg(&akm->i2c->dev, "IOCTL_SET_MODE called."); - ret = AKECS_SetMode(akm, mode); - if (ret < 0) - return ret; - break; - case ECS_IOCTL_GETDATA: - dev_vdbg(&akm->i2c->dev, "IOCTL_GETDATA called."); - ret = AKECS_GetData(akm, sensor_buf, SENSOR_DATA_SIZE); - if (ret < 0) - return ret; - break; - case ECS_IOCTL_SET_YPR: - dev_vdbg(&akm->i2c->dev, "IOCTL_SET_YPR called."); - AKECS_SetYPR(akm, ypr_buf); - break; - case ECS_IOCTL_GET_OPEN_STATUS: - dev_vdbg(&akm->i2c->dev, "IOCTL_GET_OPEN_STATUS called."); - ret = AKECS_GetOpenStatus(akm); - if (ret < 0) { - dev_err(&akm->i2c->dev, - "Get Open returns error (%d).", ret); - } - break; - case ECS_IOCTL_GET_CLOSE_STATUS: - dev_vdbg(&akm->i2c->dev, "IOCTL_GET_CLOSE_STATUS called."); - ret = AKECS_GetCloseStatus(akm); - if (ret < 0) { - dev_err(&akm->i2c->dev, - "Get Close returns error (%d).", ret); - } - break; - case ECS_IOCTL_GET_DELAY: - dev_vdbg(&akm->i2c->dev, "IOCTL_GET_DELAY called."); - mutex_lock(&akm->val_mutex); - delay[0] = akm->delay[0]; - delay[1] = akm->delay[1]; - delay[2] = akm->delay[2]; - mutex_unlock(&akm->val_mutex); - break; - case ECS_IOCTL_GET_LAYOUT: - dev_vdbg(&akm->i2c->dev, "IOCTL_GET_LAYOUT called."); - layout = akm->layout; - break; - case ECS_IOCTL_GET_OUTBIT: - dev_vdbg(&akm->i2c->dev, "IOCTL_GET_OUTBIT called."); - outbit = akm->outbit; - break; - case ECS_IOCTL_RESET: - ret = AKECS_Reset(akm, akm->rstn); - if (ret < 0) - return ret; - break; - case ECS_IOCTL_GET_ACCEL: - dev_vdbg(&akm->i2c->dev, "IOCTL_GET_ACCEL called."); - mutex_lock(&akm->accel_mutex); - acc_buf[0] = akm->accel_data[0]; - acc_buf[1] = akm->accel_data[1]; - acc_buf[2] = akm->accel_data[2]; - mutex_unlock(&akm->accel_mutex); - break; - default: - return -ENOTTY; - } - - switch (cmd) { - case ECS_IOCTL_READ: - if (copy_to_user(argp, &i2c_buf, i2c_buf[0]+1)) { - dev_err(&akm->i2c->dev, "copy_to_user failed."); - return -EFAULT; - } - break; - case ECS_IOCTL_GETDATA: - if (copy_to_user(argp, &sensor_buf, sizeof(sensor_buf))) { - dev_err(&akm->i2c->dev, "copy_to_user failed."); - return -EFAULT; - } - break; - case ECS_IOCTL_GET_OPEN_STATUS: - case ECS_IOCTL_GET_CLOSE_STATUS: - status = atomic_read(&akm->active); - if (copy_to_user(argp, &status, sizeof(status))) { - dev_err(&akm->i2c->dev, "copy_to_user failed."); - return -EFAULT; - } - break; - case ECS_IOCTL_GET_DELAY: - if (copy_to_user(argp, &delay, sizeof(delay))) { - dev_err(&akm->i2c->dev, "copy_to_user failed."); - return -EFAULT; - } - break; - case ECS_IOCTL_GET_LAYOUT: - if (copy_to_user(argp, &layout, sizeof(layout))) { - dev_err(&akm->i2c->dev, "copy_to_user failed."); - return -EFAULT; - } - break; - case ECS_IOCTL_GET_OUTBIT: - if (copy_to_user(argp, &outbit, sizeof(outbit))) { - dev_err(&akm->i2c->dev, "copy_to_user failed."); - return -EFAULT; - } - break; - case ECS_IOCTL_GET_ACCEL: - if (copy_to_user(argp, &acc_buf, sizeof(acc_buf))) { - dev_err(&akm->i2c->dev, "copy_to_user failed."); - return -EFAULT; - } - break; - default: - break; - } - - return 0; -} - -/***** akm sysfs functions ******************************************/ -static int create_device_attributes( - struct device *dev, - struct device_attribute *attrs) -{ - int i; - int err = 0; - - for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { - err = device_create_file(dev, &attrs[i]); - if (0 != err) - break; - } - - if (0 != err) { - for (; i >= 0 ; --i) - device_remove_file(dev, &attrs[i]); - } - - return err; -} - -static void remove_device_attributes( - struct device *dev, - struct device_attribute *attrs) -{ - int i; - - for (i = 0 ; NULL != attrs[i].attr.name ; ++i) - device_remove_file(dev, &attrs[i]); -} - -static int create_device_binary_attributes( - struct kobject *kobj, - struct bin_attribute *attrs) -{ - int i; - int err = 0; - - err = 0; - - for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { - err = sysfs_create_bin_file(kobj, &attrs[i]); - if (0 != err) - break; - } - - if (0 != err) { - for (; i >= 0 ; --i) - sysfs_remove_bin_file(kobj, &attrs[i]); - } - - return err; -} - -static void remove_device_binary_attributes( - struct kobject *kobj, - struct bin_attribute *attrs) -{ - int i; - - for (i = 0 ; NULL != attrs[i].attr.name ; ++i) - sysfs_remove_bin_file(kobj, &attrs[i]); -} - -static bool get_value_as_int(char const *buf, size_t size, int *value) -{ - long tmp; - - if (size == 0) - return false; - - /* maybe text format value */ - if ((buf[0] == '0') && (size > 1)) { - if ((buf[1] == 'x') || (buf[1] == 'X')) { - /* hexadecimal format */ - if (0 != strict_strtol(buf, 16, &tmp)) - return false; - } else { - /* octal format */ - if (0 != strict_strtol(buf, 8, &tmp)) - return false; - } - } else { - /* decimal format */ - if (0 != strict_strtol(buf, 10, &tmp)) - return false; - } - - if (tmp > INT_MAX) - return false; - - *value = tmp; - - return true; -} - -static bool get_value_as_int64(char const *buf, size_t size, long long *value) -{ - long long tmp; - - if (size == 0) - return false; - - /* maybe text format value */ - if ((buf[0] == '0') && (size > 1)) { - if ((buf[1] == 'x') || (buf[1] == 'X')) { - /* hexadecimal format */ - if (0 != strict_strtoll(buf, 16, &tmp)) - return false; - } else { - /* octal format */ - if (0 != strict_strtoll(buf, 8, &tmp)) - return false; - } - } else { - /* decimal format */ - if (0 != strict_strtoll(buf, 10, &tmp)) - return false; - } - - if (tmp > LLONG_MAX) - return false; - - *value = tmp; - - return true; -} - -/********************************************************************* - * - * SysFS attribute functions - * - * directory : /sys/class/compass/akm8963/ - * files : - * - enable_acc [rw] [t] : enable flag for accelerometer - * - enable_mag [rw] [t] : enable flag for magnetometer - * - enable_ori [rw] [t] : enable flag for orientation - * - delay_acc [rw] [t] : delay in nanosecond for accelerometer - * - delay_mag [rw] [t] : delay in nanosecond for magnetometer - * - delay_ori [rw] [t] : delay in nanosecond for orientation - * - accel [w] [b] : accelerometer data - * - * debug : - * - mode [w] [t] : AK8963's mode - * - bdata [r] [t] : raw data - * - asa [r] [t] : FUSEROM data - * - * [b] = binary format - * [t] = text format - */ - -/***** sysfs enable *************************************************/ -static void akm8963_sysfs_update_active_status( - struct akm8963_data *akm) -{ - uint32_t en; - mutex_lock(&akm->val_mutex); - en = akm->enable_flag; - mutex_unlock(&akm->val_mutex); - - if (en == 0) { - if (atomic_cmpxchg(&akm->active, 1, 0) == 1) { - wake_up(&akm->open_wq); - dev_dbg(akm->class_dev, "Deactivated"); - } - } else { - if (atomic_cmpxchg(&akm->active, 0, 1) == 0) { - wake_up(&akm->open_wq); - dev_dbg(akm->class_dev, "Activated"); - } - } - dev_dbg(&akm->i2c->dev, - "Status updated: enable=0x%X, active=%d", - en, atomic_read(&akm->active)); -} - -static ssize_t akm8963_sysfs_enable_show( - struct akm8963_data *akm, char *buf, int pos) -{ - int flag; - - mutex_lock(&akm->val_mutex); - flag = ((akm->enable_flag >> pos) & 1); - mutex_unlock(&akm->val_mutex); - - return sprintf(buf, "%d\n", flag); -} - -static ssize_t akm8963_sysfs_enable_store( - struct akm8963_data *akm, char const *buf, size_t count, int pos) -{ - int en = 0; - - if (NULL == buf) - return -EINVAL; - - if (0 == count) - return 0; - - if (false == get_value_as_int(buf, count, &en)) - return -EINVAL; - - en = en ? 1 : 0; - - mutex_lock(&akm->val_mutex); - akm->enable_flag &= ~(1<<pos); - akm->enable_flag |= ((uint32_t)(en))<<pos; - mutex_unlock(&akm->val_mutex); - - akm8963_sysfs_update_active_status(akm); - - return count; -} - -/***** Acceleration ***/ -static ssize_t akm8963_enable_acc_show( - struct device *dev, struct device_attribute *attr, char *buf) -{ - return akm8963_sysfs_enable_show( - dev_get_drvdata(dev), buf, ACC_DATA_FLAG); -} -static ssize_t akm8963_enable_acc_store( - struct device *dev, struct device_attribute *attr, - char const *buf, size_t count) -{ - return akm8963_sysfs_enable_store( - dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); -} - -/***** Magnetic field ***/ -static ssize_t akm8963_enable_mag_show( - struct device *dev, struct device_attribute *attr, char *buf) -{ - return akm8963_sysfs_enable_show( - dev_get_drvdata(dev), buf, MAG_DATA_FLAG); -} -static ssize_t akm8963_enable_mag_store( - struct device *dev, struct device_attribute *attr, - char const *buf, size_t count) -{ - return akm8963_sysfs_enable_store( - dev_get_drvdata(dev), buf, count, MAG_DATA_FLAG); -} - -/***** Orientation ***/ -static ssize_t akm8963_enable_ori_show( - struct device *dev, struct device_attribute *attr, char *buf) -{ - return akm8963_sysfs_enable_show( - dev_get_drvdata(dev), buf, ORI_DATA_FLAG); -} -static ssize_t akm8963_enable_ori_store( - struct device *dev, struct device_attribute *attr, - char const *buf, size_t count) -{ - return akm8963_sysfs_enable_store( - dev_get_drvdata(dev), buf, count, ORI_DATA_FLAG); -} - -/***** sysfs delay **************************************************/ -static ssize_t akm8963_sysfs_delay_show( - struct akm8963_data *akm, char *buf, int pos) -{ - int64_t val; - - mutex_lock(&akm->val_mutex); - val = akm->delay[pos]; - mutex_unlock(&akm->val_mutex); - - return sprintf(buf, "%lld\n", val); -} - -static ssize_t akm8963_sysfs_delay_store( - struct akm8963_data *akm, char const *buf, size_t count, int pos) -{ - long long val = 0; - - if (NULL == buf) - return -EINVAL; - - if (0 == count) - return 0; - - if (false == get_value_as_int64(buf, count, &val)) - return -EINVAL; - - mutex_lock(&akm->val_mutex); - akm->delay[pos] = val; - mutex_unlock(&akm->val_mutex); - - return count; -} - -/***** Accelerometer ***/ -static ssize_t akm8963_delay_acc_show( - struct device *dev, struct device_attribute *attr, char *buf) -{ - return akm8963_sysfs_delay_show( - dev_get_drvdata(dev), buf, ACC_DATA_FLAG); -} -static ssize_t akm8963_delay_acc_store( - struct device *dev, struct device_attribute *attr, - char const *buf, size_t count) -{ - return akm8963_sysfs_delay_store( - dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); -} - -/***** Magnetic field ***/ -static ssize_t akm8963_delay_mag_show( - struct device *dev, struct device_attribute *attr, char *buf) -{ - return akm8963_sysfs_delay_show( - dev_get_drvdata(dev), buf, MAG_DATA_FLAG); -} -static ssize_t akm8963_delay_mag_store( - struct device *dev, struct device_attribute *attr, - char const *buf, size_t count) -{ - return akm8963_sysfs_delay_store( - dev_get_drvdata(dev), buf, count, MAG_DATA_FLAG); -} - -/***** Orientation ***/ -static ssize_t akm8963_delay_ori_show( - struct device *dev, struct device_attribute *attr, char *buf) -{ - return akm8963_sysfs_delay_show( - dev_get_drvdata(dev), buf, ORI_DATA_FLAG); -} -static ssize_t akm8963_delay_ori_store( - struct device *dev, struct device_attribute *attr, - char const *buf, size_t count) -{ - return akm8963_sysfs_delay_store( - dev_get_drvdata(dev), buf, count, ORI_DATA_FLAG); -} - - -/***** accel (binary) ***/ -static ssize_t akm8963_bin_accel_write( - struct file *file, - struct kobject *kobj, - struct bin_attribute *attr, - char *buf, - loff_t pos, - size_t size) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct akm8963_data *akm = dev_get_drvdata(dev); - int16_t *accel_data; - - if (size == 0) - return 0; - - accel_data = (int16_t*)buf; - - mutex_lock(&akm->accel_mutex); - akm->accel_data[0] = accel_data[0]; - akm->accel_data[1] = accel_data[1]; - akm->accel_data[2] = accel_data[2]; - mutex_unlock(&akm->accel_mutex); - - dev_vdbg(&akm->i2c->dev, "accel:%d,%d,%d\n", - accel_data[0], accel_data[1], accel_data[2]); - - return size; -} - - -#ifdef AKM8963_DEBUG_IF -static ssize_t akm8963_mode_store( - struct device *dev, struct device_attribute *attr, - char const *buf, size_t count) -{ - struct akm8963_data *akm = dev_get_drvdata(dev); - int mode = 0; - - if (NULL == buf) - return -EINVAL; - - if (0 == count) - return 0; - - if (false == get_value_as_int(buf, count, &mode)) - return -EINVAL; - - if (AKECS_SetMode(akm, mode) < 0) - return -EINVAL; - - return 1; -} - -static ssize_t akm8963_bdata_show( - struct device *dev, struct device_attribute *attr, char *buf) -{ - struct akm8963_data *akm = dev_get_drvdata(dev); - char rbuf[SENSOR_DATA_SIZE]; - - mutex_lock(&akm->sensor_mutex); - memcpy(&rbuf, akm->sense_data, sizeof(rbuf)); - mutex_unlock(&akm->sensor_mutex); - - return sprintf(buf, - "0x%02X,0x%02X,0x%02X,0x%02X," - "0x%02X,0x%02X,0x%02X,0x%02X\n", - rbuf[0],rbuf[1],rbuf[2],rbuf[3], - rbuf[4],rbuf[5],rbuf[6],rbuf[7]); -} - -static ssize_t akm8963_asa_show( - struct device *dev, struct device_attribute *attr, char *buf) -{ - struct akm8963_data *akm = dev_get_drvdata(dev); - int err; - unsigned char asa[3]; - - err = AKECS_SetMode(akm, AK8963_MODE_FUSE_ACCESS); - if (err < 0) - return err; - - asa[0] = AK8963_FUSE_ASAX; - err = akm8963_i2c_rxdata(akm->i2c, asa, 3); - if (err < 0) - return err; - - err = AKECS_SetMode(akm, AK8963_MODE_POWERDOWN); - if (err < 0) - return err; - - return sprintf(buf, "0x%02X,0x%02X,0x%02X\n", - asa[0], asa[1], asa[2]); -} -#endif - -static struct device_attribute akm8963_attributes[] = { - __ATTR(enable_acc, 0660, akm8963_enable_acc_show, akm8963_enable_acc_store), - __ATTR(enable_mag, 0660, akm8963_enable_mag_show, akm8963_enable_mag_store), - __ATTR(enable_ori, 0660, akm8963_enable_ori_show, akm8963_enable_ori_store), - __ATTR(delay_acc, 0660, akm8963_delay_acc_show, akm8963_delay_acc_store), - __ATTR(delay_mag, 0660, akm8963_delay_mag_show, akm8963_delay_mag_store), - __ATTR(delay_ori, 0660, akm8963_delay_ori_show, akm8963_delay_ori_store), -#ifdef AKM8963_DEBUG_IF - __ATTR(mode, 0220, NULL, akm8963_mode_store), - __ATTR(bdata, 0440, akm8963_bdata_show, NULL), - __ATTR(asa, 0440, akm8963_asa_show, NULL), -#endif - __ATTR_NULL, -}; - -#define __BIN_ATTR(name_, mode_, size_, private_, read_, write_) \ - { \ - .attr = { .name = __stringify(name_), .mode = mode_ }, \ - .size = size_, \ - .private = private_, \ - .read = read_, \ - .write = write_, \ - } - -#define __BIN_ATTR_NULL \ - { \ - .attr = { .name = NULL }, \ - } - -static struct bin_attribute akm8963_bin_attributes[] = { - __BIN_ATTR(accel, 0220, 6, NULL, - NULL, akm8963_bin_accel_write), - __BIN_ATTR_NULL -}; - -static char const *const compass_class_name = "compass"; -static char const *const akm8963_device_name = "akm8963"; -static char const *const device_link_name = "i2c"; -static dev_t const akm8963_device_dev_t = MKDEV(MISC_MAJOR, 240); - -static int create_sysfs_interfaces(struct akm8963_data *akm) -{ - int err; - - if (NULL == akm) - return -EINVAL; - - err = 0; - - akm->compass = class_create(THIS_MODULE, compass_class_name); - if (IS_ERR(akm->compass)) { - err = PTR_ERR(akm->compass); - goto exit_class_create_failed; - } - - akm->class_dev = device_create( - akm->compass, - NULL, - akm8963_device_dev_t, - akm, - akm8963_device_name); - if (IS_ERR(akm->class_dev)) { - err = PTR_ERR(akm->class_dev); - goto exit_class_device_create_failed; - } - - err = sysfs_create_link( - &akm->class_dev->kobj, - &akm->i2c->dev.kobj, - device_link_name); - if (0 > err) - goto exit_sysfs_create_link_failed; - - err = create_device_attributes( - akm->class_dev, - akm8963_attributes); - if (0 > err) - goto exit_device_attributes_create_failed; - - err = create_device_binary_attributes( - &akm->class_dev->kobj, - akm8963_bin_attributes); - if (0 > err) - goto exit_device_binary_attributes_create_failed; - - return err; - -exit_device_binary_attributes_create_failed: - remove_device_attributes(akm->class_dev, akm8963_attributes); -exit_device_attributes_create_failed: - sysfs_remove_link(&akm->class_dev->kobj, device_link_name); -exit_sysfs_create_link_failed: - device_destroy(akm->compass, akm8963_device_dev_t); -exit_class_device_create_failed: - akm->class_dev = NULL; - class_destroy(akm->compass); -exit_class_create_failed: - akm->compass = NULL; - return err; -} - -static void remove_sysfs_interfaces(struct akm8963_data *akm) -{ - if (NULL == akm) - return; - - if (NULL != akm->class_dev) { - remove_device_binary_attributes( - &akm->class_dev->kobj, - akm8963_bin_attributes); - remove_device_attributes( - akm->class_dev, - akm8963_attributes); - sysfs_remove_link( - &akm->class_dev->kobj, - device_link_name); - akm->class_dev = NULL; - } - if (NULL != akm->compass) { - device_destroy( - akm->compass, - akm8963_device_dev_t); - class_destroy(akm->compass); - akm->compass = NULL; - } -} - - -/***** akm input device functions ***********************************/ -static int akm8963_input_init( - struct input_dev **input) -{ - int err = 0; - - /* Declare input device */ - *input = input_allocate_device(); - if (!*input) - return -ENOMEM; - - /* Setup input device */ - set_bit(EV_ABS, (*input)->evbit); - /* Accelerometer (720 x 16G)*/ - input_set_abs_params(*input, ABS_X, - -11520, 11520, 0, 0); - input_set_abs_params(*input, ABS_Y, - -11520, 11520, 0, 0); - input_set_abs_params(*input, ABS_Z, - -11520, 11520, 0, 0); - input_set_abs_params(*input, ABS_THROTTLE, - 0, 3, 0, 0); - /* Magnetic field (-81900, 81900) -> limited to 16bit*/ - input_set_abs_params(*input, ABS_RX, - -32768, 32767, 0, 0); - input_set_abs_params(*input, ABS_RY, - -32768, 32767, 0, 0); - input_set_abs_params(*input, ABS_RZ, - -32768, 32767, 0, 0); - input_set_abs_params(*input, ABS_RUDDER, - 0, 3, 0, 0); - /* Orientation (yaw:0,360 pitch:-180,180 roll:-90,90) */ - input_set_abs_params(*input, ABS_HAT0X, - 0, 23040, 0, 0); - input_set_abs_params(*input, ABS_HAT0Y, - -11520, 11520, 0, 0); - input_set_abs_params(*input, ABS_HAT1X, - -5760, 5760, 0, 0); - input_set_abs_params(*input, ABS_HAT1Y, - 0, 3, 0, 0); - - /* Set name */ - (*input)->name = "compass"; - - /* Register */ - err = input_register_device(*input); - if (err) { - input_free_device(*input); - return err; - } - - return err; -} - -/***** akm functions ************************************************/ - -static irqreturn_t akm8963_irq(int irq, void *handle) -{ - struct akm8963_data *akm = handle; - char buffer[SENSOR_DATA_SIZE]; - int err; - - memset(buffer, 0, sizeof(buffer)); - buffer[0] = AK8963_REG_ST1; - err = akm8963_i2c_rxdata(akm->i2c, buffer, SENSOR_DATA_SIZE); - if (err < 0) { - dev_err(&akm->i2c->dev, "%s failed.", __func__); - goto work_func_end; - } - /* Check ST bit */ - if ((buffer[0] & 0x01) != 0x01) { - dev_err(&akm->i2c->dev, "%s ST is not set.", __func__); - goto work_func_end; - } - - mutex_lock(&akm->sensor_mutex); - memcpy(akm->sense_data, buffer, SENSOR_DATA_SIZE); - mutex_unlock(&akm->sensor_mutex); - - atomic_set(&akm->drdy, 1); - atomic_set(&akm->is_busy, 0); - wake_up(&akm->drdy_wq); - -work_func_end: - return IRQ_HANDLED; -} - -static void akm8963_delayed_work(struct work_struct *work) -{ - struct akm8963_data *akm = container_of( - work, struct akm8963_data, work.work); - - akm8963_irq(akm->irq, akm); -} - -static int akm8963_suspend(struct device *dev) -{ - struct akm8963_data *akm = dev_get_drvdata(dev); - dev_dbg(&akm->i2c->dev, "suspended\n"); - - return 0; -} - -static int akm8963_resume(struct device *dev) -{ - struct akm8963_data *akm = dev_get_drvdata(dev); - dev_dbg(&akm->i2c->dev, "resumed\n"); - - return 0; -} - -int akm8963_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct akm8963_platform_data *pdata; - int err = 0; - int i; - - dev_dbg(&client->dev, "start probing."); - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - dev_err(&client->dev, "%s: check_functionality failed.", __func__); - err = -ENODEV; - goto exit0; - } - - /* Allocate memory for driver data */ - s_akm = kzalloc(sizeof(struct akm8963_data), GFP_KERNEL); - if (!s_akm) { - dev_err(&client->dev, "%s: memory allocation failed.", __func__); - err = -ENOMEM; - goto exit1; - } - - /***** Set layout information *****/ - pdata = client->dev.platform_data; - if (pdata) { - /* Platform data is available. copy its value to local. */ - s_akm->layout = pdata->layout; - s_akm->outbit = pdata->outbit; - s_akm->rstn = pdata->gpio_RST; - } else { - /* Platform data is not available. - Layout and Outbit information should be set by each application. */ - dev_dbg(&client->dev, "%s: No platform data.", __func__); - s_akm->layout = 0; - s_akm->outbit = 0; - s_akm->rstn = 0; - } - - /***** I2C initialization *****/ - s_akm->i2c = client; - /* check connection */ - err = akm8963_i2c_check_device(client); - if (err < 0) - goto exit2; - /* set client data */ - i2c_set_clientdata(client, s_akm); - - - /***** input *****/ - err = akm8963_input_init(&s_akm->input); - if (err) { - dev_err(&client->dev, - "%s: input_dev register failed", __func__); - goto exit3; - } - input_set_drvdata(s_akm->input, s_akm); - - - /**** initialize variables in akm8963_data *****/ - init_waitqueue_head(&s_akm->drdy_wq); - init_waitqueue_head(&s_akm->open_wq); - - mutex_init(&s_akm->sensor_mutex); - mutex_init(&s_akm->accel_mutex); - mutex_init(&s_akm->val_mutex); - - atomic_set(&s_akm->active, 0); - atomic_set(&s_akm->is_busy, 0); - atomic_set(&s_akm->drdy, 0); - atomic_set(&s_akm->suspend, 0); - - s_akm->enable_flag = 0; - for (i=0; i<AKM_NUM_SENSORS; i++) - s_akm->delay[i] = -1; - - - /***** IRQ setup *****/ - s_akm->irq = client->irq; - - - if (s_akm->irq == 0) { - dev_dbg(&client->dev, "%s: IRQ is not set.", __func__); - /* Use timer to notify measurement end */ - INIT_DELAYED_WORK(&s_akm->work, akm8963_delayed_work); - } else { - err = request_threaded_irq( - s_akm->irq, - NULL, - akm8963_irq, - IRQF_TRIGGER_HIGH|IRQF_ONESHOT, - dev_name(&client->dev), - s_akm); - if (err < 0) { - dev_err(&client->dev, - "%s: request irq failed.", __func__); - goto exit4; - } - } - - /***** misc *****/ - err = misc_register(&akm8963_dev); - if (err) { - dev_err(&client->dev, - "%s: akm8963_dev register failed", __func__); - goto exit5; - } - - /***** sysfs *****/ - err = create_sysfs_interfaces(s_akm); - if (0 > err) { - dev_err(&client->dev, - "%s: create sysfs failed.", __func__); - goto exit6; - } - - dev_info(&client->dev, "successfully probed."); - return 0; - -exit6: - misc_deregister(&akm8963_dev); -exit5: - if (s_akm->irq) - free_irq(s_akm->irq, s_akm); -exit4: - input_unregister_device(s_akm->input); -exit3: -exit2: - kfree(s_akm); -exit1: -exit0: - return err; -} - -static int akm8963_remove(struct i2c_client *client) -{ - struct akm8963_data *akm = i2c_get_clientdata(client); - - remove_sysfs_interfaces(akm); - if (misc_deregister(&akm8963_dev) < 0) - dev_err(&client->dev, "misc deregister failed."); - if (akm->irq) - free_irq(akm->irq, akm); - input_unregister_device(akm->input); - kfree(akm); - dev_info(&client->dev, "successfully removed."); - return 0; -} - -static const struct i2c_device_id akm8963_id[] = { - {AKM8963_I2C_NAME, 0 }, - { } -}; - -static const struct dev_pm_ops akm8963_pm_ops = { - .suspend = akm8963_suspend, - .resume = akm8963_resume, -}; - -static struct i2c_driver akm8963_driver = { - .probe = akm8963_probe, - .remove = akm8963_remove, - .id_table = akm8963_id, - .driver = { - .name = AKM8963_I2C_NAME, - .pm = &akm8963_pm_ops, - }, -}; - -static int __init akm8963_init(void) -{ - printk(KERN_INFO "AKM8963 compass driver: initialize."); - return i2c_add_driver(&akm8963_driver); -} - -static void __exit akm8963_exit(void) -{ - printk(KERN_INFO "AKM8963 compass driver: release."); - i2c_del_driver(&akm8963_driver); -} - -module_init(akm8963_init); -module_exit(akm8963_exit); - -MODULE_AUTHOR("viral wang <viral_wang@htc.com>"); -MODULE_DESCRIPTION("AKM8963 compass driver"); -MODULE_LICENSE("GPL"); - |