diff options
Diffstat (limited to 'drivers/sensorhub/ssp_ak8963c.c')
-rw-r--r-- | drivers/sensorhub/ssp_ak8963c.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/drivers/sensorhub/ssp_ak8963c.c b/drivers/sensorhub/ssp_ak8963c.c new file mode 100644 index 0000000..5a462b9 --- /dev/null +++ b/drivers/sensorhub/ssp_ak8963c.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * 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. + * + */ +#include "ssp.h" + +/*************************************************************************/ +/* AKM Daemon Library ioctl */ +/*************************************************************************/ + +static int akmd_copy_in(unsigned int cmd, void __user *argp, + void *buf, size_t buf_size) +{ + if (!(cmd & IOC_IN)) + return 0; + if (_IOC_SIZE(cmd) > buf_size) + return -EINVAL; + if (copy_from_user(buf, argp, _IOC_SIZE(cmd))) + return -EFAULT; + return 0; +} + +static int akmd_copy_out(unsigned int cmd, void __user *argp, + void *buf, size_t buf_size) +{ + if (!(cmd & IOC_OUT)) + return 0; + if (_IOC_SIZE(cmd) > buf_size) + return -EINVAL; + if (copy_to_user(argp, buf, _IOC_SIZE(cmd))) + return -EFAULT; + return 0; +} + +static long akmd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int iRet; + void __user *argp = (void __user *)arg; + struct ssp_data *data = container_of(file->private_data, + struct ssp_data, akmd_device); + + union { + u8 uData[8]; + u8 uMagData[8]; + u8 uFuseData[3]; + int iAccData[3]; + } akmdbuf; + + iRet = akmd_copy_in(cmd, argp, akmdbuf.uData, sizeof(akmdbuf)); + if (iRet) + return iRet; + + switch (cmd) { + case ECS_IOCTL_GET_MAGDATA: + akmdbuf.uMagData[0] = 1; + akmdbuf.uMagData[1] = data->buf[GEOMAGNETIC_SENSOR].x & 0xff; + akmdbuf.uMagData[2] = data->buf[GEOMAGNETIC_SENSOR].x >> 8; + akmdbuf.uMagData[3] = data->buf[GEOMAGNETIC_SENSOR].y & 0xff; + akmdbuf.uMagData[4] = data->buf[GEOMAGNETIC_SENSOR].y >> 8; + akmdbuf.uMagData[5] = data->buf[GEOMAGNETIC_SENSOR].z & 0xff; + akmdbuf.uMagData[6] = data->buf[GEOMAGNETIC_SENSOR].z >> 8; + akmdbuf.uMagData[7] = 0x10; + break; + case ECS_IOCTL_GET_ACCDATA: + akmdbuf.iAccData[0] = data->buf[ACCELEROMETER_SENSOR].x; + akmdbuf.iAccData[1] = data->buf[ACCELEROMETER_SENSOR].y; + akmdbuf.iAccData[2] = data->buf[ACCELEROMETER_SENSOR].z; + break; + case ECS_IOCTL_GET_FUSEROMDATA: + akmdbuf.uFuseData[0] = data->uFuseRomData[0]; + akmdbuf.uFuseData[1] = data->uFuseRomData[1]; + akmdbuf.uFuseData[2] = data->uFuseRomData[2]; + break; + default: + return -ENOTTY; + } + + if (iRet < 0) + return iRet; + + return akmd_copy_out(cmd, argp, akmdbuf.uData, sizeof(akmdbuf)); +} + +static const struct file_operations akmd_fops = { + .owner = THIS_MODULE, + .open = nonseekable_open, + .unlocked_ioctl = akmd_ioctl, +}; + +void initialize_magnetic(struct ssp_data *data) +{ + data->akmd_device.minor = MISC_DYNAMIC_MINOR; + data->akmd_device.name = "akm8963"; + data->akmd_device.fops = &akmd_fops; +} |