@@ -1069,6 +1069,13 @@ config SENSORS_WPCE775X
This driver provides support for the Winbond WPCE775XX Embedded
Controller, which provides lcd backlight, LEDs, and Battery control.
+config SENSORS_HMC5843
+ tristate "HMC5843 Compass Sensor Driver"
+ depends on I2C && ARCH_MSM_SCORPION
+ default n
+ help
+ HMC5843 Compass Sensor Driver implemented by Quanta.
+
config SENSORS_BOSCH_BMA150
tristate "SMB380/BMA150 acceleration sensor support"
depends on I2C
@@ -96,6 +96,7 @@ obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
obj-$(CONFIG_SENSORS_ISL29011) += isl29011.o
obj-$(CONFIG_SENSORS_WPCE775X) += wpce775x.o
obj-$(CONFIG_SENSORS_BOSCH_BMA150) += bma150.o
+obj-$(CONFIG_SENSORS_HMC5843) += hmc5843.o
ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
new file mode 100755
@@ -0,0 +1,501 @@
+/* Quanta I2C Compass sensor Driver
+ *
+ * Copyright (C) 2009 Quanta Computer Inc.
+ * Author: Ivan Chang <Ivan.Chang@quantatw.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.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include "hmc5843.h"
+
+#define MSENSOR_DRV_NAME "hmc5843"
+#define MSENSOR_DEV_NAME "hmc5843"
+#define MSENSOR_DEV_MINOR MISC_DYNAMIC_MINOR
+#define MSENSOR_DATA_BUF_LEN 3
+
+#define MSENSOR_A_REG 0
+#define MSENSOR_A_MEASURE_MASK 0x03
+#define MSENSOR_A_RATE_MASK 0x1c
+#define MSENSOR_A_RATE_SHIFT 2
+#define MSENSOR_B_REG 1
+#define MSENSOR_B_GAIN_MASK 0xe0
+#define MSENSOR_B_GAIN_SHIFT 5
+#define MSENSOR_MODE_REG 2
+#define MSENSOR_MODE_MASK 0x03
+#define MSENSOR_MODE_CONTINU 0
+#define MSENSOR_MODE_SINGLE 1
+#define MSENSOR_MODE_IDLE 2
+#define MSENSOR_MODE_SLEEP 3
+#define MSENSOR_X_DATA_REG 3
+#define MSENSOR_Y_DATA_REG 5
+#define MSENSOR_Z_DATA_REG 7
+#define MSENSOR_STATUS_REG 9
+#define MSENSOR_STATUS_REN 0x04
+#define MSENSOR_STATUS_LOCK 0x02
+#define MSENSOR_STATUS_RDY 0x01
+#define MSENSOR_ID_REG_A 10
+#define MSENSOR_ID_REG_B 11
+#define MSENSOR_ID_REG_C 12
+
+/*-----------------------------------------------------------------------------
+ * Global variables
+ *---------------------------------------------------------------------------*/
+/* General structure to hold the driver data */
+struct msensor_drv_data {
+ struct i2c_client *client;
+ struct mutex lock;
+ struct miscdevice msensor_dev;
+ s16 msensor_data[3];
+ u8 rate;
+ u8 measure;
+ u8 gain;
+ u8 mode;
+ u8 reg_idx;
+};
+
+static struct msensor_drv_data *g_mdrv_data;
+
+static int __devinit msensor_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int __devexit msensor_remove(struct i2c_client *client);
+
+/*-----------------------------------------------------------------------------
+ * Low level functions
+ *---------------------------------------------------------------------------*/
+static int msensor_set_register(struct i2c_client *client,
+ u8 reg, u8 reg_value)
+{
+ struct msensor_drv_data *pdata = i2c_get_clientdata(client);
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, reg, reg_value);
+ if (ret == 0) {
+ switch (reg) {
+ case MSENSOR_A_REG:
+ pdata->rate = (reg_value & MSENSOR_A_RATE_MASK) >>
+ MSENSOR_A_RATE_SHIFT;
+ pdata->measure = reg_value & MSENSOR_A_MEASURE_MASK;
+ break;
+ case MSENSOR_B_REG:
+ pdata->gain = (reg_value & MSENSOR_B_GAIN_MASK) >>
+ MSENSOR_B_GAIN_SHIFT;
+ break;
+ case MSENSOR_MODE_REG:
+ pdata->mode = reg_value & MSENSOR_MODE_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+ pdata->reg_idx = reg + 1;
+ }
+ return ret;
+}
+
+static int msensor_get_adc_value(struct i2c_client *client)
+{
+ struct msensor_drv_data *pdata = i2c_get_clientdata(client);
+ u8 raw_data[6];
+ u8 raw_status;
+ int ret, i;
+
+ if (pdata->reg_idx != MSENSOR_X_DATA_REG) {
+ raw_data[0] = MSENSOR_X_DATA_REG;
+ ret = i2c_master_send(client, raw_data, 1);
+ if (ret != 1) {
+ dev_err(&client->dev,"[M-sensor] Set reg_idx failed\n");
+ return ret;
+ }
+ pdata->reg_idx = MSENSOR_X_DATA_REG;
+ }
+
+ ret = i2c_master_recv(client, raw_data, 6);
+ if (ret != 6) {
+ dev_err(&client->dev,
+ "[M-sensor] Get value failed with ret = %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = i2c_master_recv(client, &raw_status, 1);
+ if (ret != 1) {
+ dev_err(&client->dev,
+ "[M-sensor] Get status failed with ret = %d\n",
+ ret);
+ return ret;
+ }
+
+ for (i = 0; i < MSENSOR_DATA_BUF_LEN ; i++) {
+ pdata->msensor_data[i] = raw_data[2*i+1] |
+ (s8)raw_data[2*i] << 8;
+ }
+
+ dev_dbg(&client->dev,"qci-msensor: X = %d \n", pdata->msensor_data[0]);
+ dev_dbg(&client->dev,"qci-msensor: Y = %d \n", pdata->msensor_data[1]);
+ dev_dbg(&client->dev,"qci-msensor: Z = %d \n", pdata->msensor_data[2]);
+ return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * File Operation functions
+ *---------------------------------------------------------------------------*/
+static ssize_t msensor_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *offset)
+{
+ struct msensor_drv_data *pdata = file->private_data;
+ int ret1 = 0;
+ int ret2 = 0;
+
+ mutex_lock(&pdata->lock);
+ ret1 = msensor_get_adc_value(pdata->client);
+ ret2 = copy_to_user(userbuf, pdata->msensor_data, count);
+ mutex_unlock(&pdata->lock);
+ if (ret1 != 0 || ret2 != 0) {
+ dev_err(&pdata->client->dev,"[M-sensor] read data failed!\n");
+ return -EFAULT;
+ }
+ return count;
+}
+
+static int msensor_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long param)
+{
+ struct msensor_drv_data *pdata = file->private_data;
+ void __user *argp = (void __user *)param;
+ int ret = 0;
+ int ret1 = 0;
+ int ret2 = 0;
+ int ret3 = 0;
+ u8 rate, measure, gain, mode;
+ u8 reg_value;
+
+ switch (cmd) {
+ case GET_RATE:
+ mutex_lock(&pdata->lock);
+ ret = copy_to_user(argp, &pdata->rate, sizeof(u8));
+ mutex_unlock(&pdata->lock);
+ if (ret != 0) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Get rate copy to user failed!\n");
+ return -EFAULT;
+ }
+ dev_dbg(&pdata->client->dev,
+ "[M-sensor] Get rate with value %d\n",
+ pdata->rate);
+ break;
+ case SET_RATE:
+ if (copy_from_user(&rate, argp, sizeof(rate))) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Fetch rate from user error\n");
+ return -EINVAL;
+ }
+ mutex_lock(&pdata->lock);
+ reg_value = pdata->measure | ((rate & MSENSOR_A_RATE_MASK) <<
+ MSENSOR_A_RATE_SHIFT);
+ ret = msensor_set_register(pdata->client,
+ MSENSOR_A_REG,
+ reg_value);
+ mutex_unlock(&pdata->lock);
+ if (ret < 0) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Set rate error\n");
+ return -EFAULT;
+ }
+ break;
+ case GET_MEASURE:
+ mutex_lock(&pdata->lock);
+ ret = copy_to_user(argp, &pdata->measure, sizeof(u8));
+ mutex_unlock(&pdata->lock);
+ if (ret != 0) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Get measure"
+ "copy to user failed!\n");
+ return -EFAULT;
+ }
+ dev_dbg(&pdata->client->dev,"[M-sensor] Get measure with value %d\n",
+ pdata->measure);
+ break;
+ case SET_MEASURE:
+ if (copy_from_user(&measure, argp, sizeof(measure))) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Fetch measure from user error\n");
+ return -EINVAL;
+ }
+ mutex_lock(&pdata->lock);
+ reg_value = (pdata->rate << MSENSOR_A_RATE_MASK) |
+ (measure & MSENSOR_A_MEASURE_MASK);
+ ret = msensor_set_register(pdata->client,
+ MSENSOR_A_REG,
+ reg_value);
+ mutex_unlock(&pdata->lock);
+ if (ret < 0) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Set measure error\n");
+ return -EFAULT;
+ }
+ break;
+ case GET_GAIN:
+ mutex_lock(&pdata->lock);
+ ret = copy_to_user(argp, &pdata->gain, sizeof(u8));
+ mutex_unlock(&pdata->lock);
+ if (ret != 0) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Get gain copy to user failed!\n");
+ return -EFAULT;
+ }
+ dev_dbg(&pdata->client->dev,
+ "[M-sensor] Get gain with value %d\n", pdata->gain);
+ break;
+ case SET_GAIN:
+ if (copy_from_user(&gain, argp, sizeof(gain))) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Fetch mode from user error\n");
+ return -EINVAL;
+ }
+ mutex_lock(&pdata->lock);
+ ret = msensor_set_register(pdata->client,
+ MSENSOR_B_REG,
+ ((gain & MSENSOR_B_GAIN_MASK) <<
+ MSENSOR_B_GAIN_SHIFT));
+ mutex_unlock(&pdata->lock);
+ if (ret < 0) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Set gain error\n");
+ return -EFAULT;
+ }
+ break;
+ case GET_MODE:
+ mutex_lock(&pdata->lock);
+ ret = copy_to_user(argp, &pdata->mode, sizeof(u8));
+ mutex_unlock(&pdata->lock);
+ if (ret != 0) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Get mode copy to user failed!\n");
+ return -EFAULT;
+ }
+ dev_dbg(&pdata->client->dev,
+ "[M-sensor] Get mode with value %d\n", pdata->mode);
+ break;
+ case SET_MODE:
+ if (copy_from_user(&mode, argp, sizeof(mode))) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Fetch mode from user error\n");
+ return -EINVAL;
+ }
+ mutex_lock(&pdata->lock);
+ ret = msensor_set_register(pdata->client,
+ MSENSOR_MODE_REG,
+ mode & MSENSOR_MODE_MASK);
+ mutex_unlock(&pdata->lock);
+ if (ret < 0) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Set mode error\n");
+ return -EFAULT;
+ }
+ break;
+ case SELF_TEST:
+ mutex_lock(&pdata->lock);
+ ret1 = msensor_set_register(pdata->client,
+ MSENSOR_A_REG,
+ 0x11);
+ msleep(30);
+ ret2 = msensor_set_register(pdata->client,
+ MSENSOR_B_REG,
+ 0x20);
+ msleep(30);
+ ret3 = msensor_set_register(pdata->client,
+ MSENSOR_MODE_REG,
+ 0x01);
+ msleep(30);
+ if ((ret1 < 0) || (ret2 < 0) || (ret3 < 0)) {
+ mutex_unlock(&pdata->lock);
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Set mode register error\n");
+ return -EFAULT;
+ }
+ msleep(100);
+
+ ret1 = msensor_get_adc_value(pdata->client);
+ ret2 = copy_to_user(argp,
+ pdata->msensor_data,
+ sizeof(signed short)*3);
+ if (ret1 != 0 || ret2 != 0) {
+ mutex_unlock(&pdata->lock);
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Copy to user failed!\n");
+ return -EFAULT;
+ }
+
+ msleep(200);
+ ret1 = msensor_set_register(pdata->client,
+ MSENSOR_A_REG,
+ 0x10);
+ msleep(35);
+ ret2 = msensor_set_register(pdata->client,
+ MSENSOR_B_REG,
+ 0x20);
+ msleep(35);
+ ret3 = msensor_set_register(pdata->client,
+ MSENSOR_MODE_REG,
+ 0x00);
+ msleep(35);
+ mutex_unlock(&pdata->lock);
+ if ((ret1 < 0) || (ret2 < 0) || (ret3 < 0)) {
+ dev_err(&pdata->client->dev,
+ "[M-sensor] Set mode register error\n");
+ return -EFAULT;
+ }
+ break;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int msensor_open(struct inode *inode, struct file *file)
+{
+ file->private_data = g_mdrv_data;
+ return 0;
+}
+
+static int msensor_close(struct inode *inode, struct file *file)
+{
+ file->private_data = NULL;
+ return 0;
+}
+
+static const struct file_operations msensor_ops = {
+ .owner = THIS_MODULE,
+ .read = msensor_read,
+ .open = msensor_open,
+ .release = msensor_close,
+ .ioctl = msensor_ioctl,
+};
+
+/*-----------------------------------------------------------------------------
+ * I2C Driver functions
+ *---------------------------------------------------------------------------*/
+static const struct i2c_device_id msensor_idtable[] = {
+ { MSENSOR_DRV_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, msensor_idtable);
+#ifdef CONFIG_PM
+static int msensor_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int msensor_resume(struct device *dev)
+{
+ return 0;
+}
+
+static struct dev_pm_ops msensor_pm_ops = {
+ .suspend = msensor_suspend,
+ .resume = msensor_resume,
+};
+
+#endif
+static struct i2c_driver msensor_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = MSENSOR_DRV_NAME,
+#ifdef CONFIG_PM
+ .pm = &msensor_pm_ops,
+#endif
+ },
+ .probe = msensor_probe,
+ .remove = msensor_remove,
+ .id_table = msensor_idtable,
+};
+
+static int __devinit msensor_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct msensor_drv_data *pdata = 0;
+ pdata = kzalloc(sizeof(struct msensor_drv_data), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ g_mdrv_data = pdata;
+ i2c_set_clientdata(client, pdata);
+ pdata->client = client;
+ strlcpy(pdata->client->name, MSENSOR_DRV_NAME, I2C_NAME_SIZE);
+ client->driver = &msensor_driver;
+
+ pdata->msensor_dev.minor = MSENSOR_DEV_MINOR;
+ pdata->msensor_dev.name = MSENSOR_DEV_NAME;
+ pdata->msensor_dev.fops = &msensor_ops;
+
+ mutex_init(&pdata->lock);
+
+ msensor_set_register(client, MSENSOR_A_REG, 0x10);
+ msensor_set_register(client, MSENSOR_B_REG, 0x20);
+ msensor_set_register(client, MSENSOR_MODE_REG, 0x00);
+ msleep(100);
+
+ ret = misc_register(&pdata->msensor_dev);
+ if (ret) {
+ dev_err(&client->dev,
+ "[M-sensor] Misc device register failed\n");
+ goto misc_register_fail;
+ }
+
+ dev_dbg(&client->dev,"[M-sensor] Probe successful \n");
+ return 0;
+
+misc_register_fail:
+ i2c_set_clientdata(client, NULL);
+ kfree(pdata);
+ return ret;
+}
+
+static int __devexit msensor_remove(struct i2c_client *client)
+{
+ struct msensor_drv_data *pdata;
+
+ pdata = i2c_get_clientdata(client);
+ misc_deregister(&pdata->msensor_dev);
+ kfree(pdata);
+ return 0;
+}
+
+static int __init msensor_init(void)
+{
+ return i2c_add_driver(&msensor_driver);
+}
+
+static void __exit msensor_exit(void)
+{
+ i2c_del_driver(&msensor_driver);
+}
+
+module_init(msensor_init);
+module_exit(msensor_exit);
+
+MODULE_AUTHOR("Quanta Computer Inc.");
+MODULE_DESCRIPTION("Quanta I2C M-Sensor Driver");
+MODULE_LICENSE("GPL v2");
+
new file mode 100755
@@ -0,0 +1,37 @@
+/* Quanta I2C Compass sensor Driver Header File
+ *
+ * Copyright (C) 2009 Quanta Computer Inc.
+ * Author: Ivan Chang <Ivan.Chang@quantatw.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.
+ *
+ */
+#ifndef HMC5843_DRV_H
+#define HMC5843_DRV_H
+
+#include <linux/ioctl.h>
+
+/*===========================================================================
+ IOCTLS
+===========================================================================*/
+#define HMC5843_IOC_MAGIC 0xe5
+
+#define GET_RATE _IOWR(HMC5843_IOC_MAGIC, 0, unsigned long)
+#define SET_RATE _IOWR(HMC5843_IOC_MAGIC, 1, unsigned long)
+#define GET_MEASURE _IOWR(HMC5843_IOC_MAGIC, 2, unsigned long)
+#define SET_MEASURE _IOWR(HMC5843_IOC_MAGIC, 3, unsigned long)
+#define GET_GAIN _IOWR(HMC5843_IOC_MAGIC, 4, unsigned long)
+#define SET_GAIN _IOWR(HMC5843_IOC_MAGIC, 5, unsigned long)
+#define GET_MODE _IOWR(HMC5843_IOC_MAGIC, 6, unsigned long)
+#define SET_MODE _IOWR(HMC5843_IOC_MAGIC, 7, unsigned long)
+#define SELF_TEST _IOWR(HMC5843_IOC_MAGIC, 8, unsigned long)
+
+#endif
+