summaryrefslogtreecommitdiff
path: root/drivers/hwmon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig39
-rw-r--r--drivers/hwmon/Makefile6
-rw-r--r--drivers/hwmon/da9052-adc.c644
-rw-r--r--drivers/hwmon/isl29003.c439
-rw-r--r--drivers/hwmon/max17135-hwmon.c173
-rw-r--r--drivers/hwmon/mxc_mma7450.c788
-rw-r--r--drivers/hwmon/mxc_mma8450.c390
-rw-r--r--drivers/hwmon/mxc_mma8451.c371
8 files changed, 2850 insertions, 0 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index e19cf8eb6ccf..b0fdae27b74c 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -300,6 +300,16 @@ config SENSORS_ATXP1
This driver can also be built as a module. If so, the module
will be called atxp1.
+config SENSORS_DA9052
+ tristate "Dialog DA9052 HWMon"
+ depends on PMIC_DA9052
+ help
+ Say y here to support the ADC found on
+ Dialog Semiconductor DA9052 PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called da9052_hwmon.
+
config SENSORS_DS1621
tristate "Dallas Semiconductor DS1621 and DS1625"
depends on I2C
@@ -652,6 +662,15 @@ config SENSORS_MAX1619
This driver can also be built as a module. If so, the module
will be called max1619.
+config SENSORS_MAX17135
+ tristate "Maxim MAX17135"
+ depends on I2C
+ help
+ If you say yes here you get support for MAX17135 PMIC sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called max17135_sensor.
+
config SENSORS_MAX6650
tristate "Maxim MAX6650 sensor chip"
depends on I2C && EXPERIMENTAL
@@ -1166,4 +1185,24 @@ config SENSORS_LIS3LV02D
endif # ACPI
+config MXC_MMA7450
+ tristate "MMA7450 device driver"
+ depends on MACH_MX31_3DS || MACH_MX23EVK
+ default n
+
+config SENSORS_ISL29003
+ tristate "ISL29003 Light Sensor"
+ depends on MACH_MX37_3DS || MACH_MX51_3DS
+ default y
+
+config MXC_MMA8450
+ tristate "MMA8450 device driver"
+ depends on I2C
+ default y
+
+config MXC_MMA8451
+ tristate "MMA8451 device driver"
+ depends on I2C
+ default y
+
endif # HWMON
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 2138ceb1a713..0dfdc7826dfa 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_SENSORS_AMS) += ams/
obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
+obj-$(CONFIG_SENSORS_DA9052) += da9052-adc.o
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
@@ -78,6 +79,7 @@ obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
+obj-$(CONFIG_SENSORS_MAX17135) += max17135-hwmon.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
@@ -103,6 +105,10 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
+obj-$(CONFIG_SENSORS_ISL29003) += isl29003.o
+obj-$(CONFIG_MXC_MMA7450) += mxc_mma7450.o
+obj-$(CONFIG_MXC_MMA8450) += mxc_mma8450.o
+obj-$(CONFIG_MXC_MMA8451) += mxc_mma8451.o
ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/hwmon/da9052-adc.c b/drivers/hwmon/da9052-adc.c
new file mode 100644
index 000000000000..647e580e2131
--- /dev/null
+++ b/drivers/hwmon/da9052-adc.c
@@ -0,0 +1,644 @@
+/*
+ * da9052-adc.c -- ADC Driver for Dialog DA9052
+ *
+ * Copyright(c) 2009 Dialog Semiconductor Ltd.
+ *
+ * Author: Dialog Semiconductor Ltd <dchen@diasemi.com>
+ *
+ * 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.
+ *
+ */
+#include <linux/platform_device.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/adc.h>
+
+#define DRIVER_NAME "da9052-adc"
+
+static const char *input_names[] = {
+ [DA9052_ADC_VDDOUT] = "VDDOUT",
+ [DA9052_ADC_ICH] = "CHARGING CURRENT",
+ [DA9052_ADC_TBAT] = "BATTERY TEMP",
+ [DA9052_ADC_VBAT] = "BATTERY VOLTAGE",
+ [DA9052_ADC_ADCIN4] = "ADC INPUT 4",
+ [DA9052_ADC_ADCIN5] = "ADC INPUT 5",
+ [DA9052_ADC_ADCIN6] = "ADC INPUT 6",
+ [DA9052_ADC_TSI] = "TSI",
+ [DA9052_ADC_TJUNC] = "BATTERY JUNCTION TEMP",
+ [DA9052_ADC_VBBAT] = "BACK-UP BATTERY TEMP",
+};
+
+
+int da9052_manual_read(struct da9052 *da9052,
+ unsigned char channel)
+{
+ unsigned char man_timeout_cnt = DA9052_ADC_MAX_MANCONV_RETRY_COUNT;
+ struct da9052_ssc_msg msg;
+ unsigned short calc_data;
+ unsigned int ret;
+ u16 data = 0;
+
+ msg.addr = DA9052_ADCMAN_REG;
+ msg.data = channel;
+ msg.data = (msg.data | DA9052_ADCMAN_MANCONV);
+
+ mutex_lock(&da9052->manconv_lock);
+ da9052_lock(da9052);
+
+ ret = da9052->write(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+
+ /* Wait for the event */
+ do {
+ msg.addr = DA9052_ADCCONT_REG;
+ msg.data = 0;
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+
+ if (DA9052_ADCCONT_ADCMODE & msg.data)
+ msleep(1);
+ else
+ msleep(10);
+
+ msg.addr = DA9052_ADCMAN_REG;
+ msg.data = 0;
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+
+ /* Counter to avoid endless while loop */
+ man_timeout_cnt--;
+ if (man_timeout_cnt == 1) {
+ if (!(msg.data & DA9052_ADCMAN_MANCONV))
+ break;
+ else
+ goto err_ssc_comm;
+ }
+ /* Wait until the MAN_CONV bit is cleared to zero */
+ } while (msg.data & DA9052_ADCMAN_MANCONV);
+
+ msg.addr = DA9052_ADCRESH_REG;
+ msg.data = 0;
+
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+
+ calc_data = (unsigned short)msg.data;
+ data = (calc_data << 2);
+
+ msg.addr = DA9052_ADCRESL_REG;
+ msg.data = 0;
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+
+ /* Clear first 14 bits before ORing */
+ calc_data = (unsigned short)msg.data & 0x0003;
+ data |= calc_data;
+
+ mutex_unlock(&da9052->manconv_lock);
+
+ return data;
+err_ssc_comm:
+ mutex_unlock(&da9052->manconv_lock);
+ da9052_unlock(da9052);
+ return -EIO;
+}
+EXPORT_SYMBOL(da9052_manual_read);
+
+int da9052_read_tjunc(struct da9052 *da9052, char *buf)
+{
+ struct da9052_ssc_msg msg;
+ unsigned char temp;
+ int ret;
+
+ msg.addr = DA9052_TJUNCRES_REG;
+ msg.data = 0;
+
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+
+ temp = msg.data;
+
+ msg.addr = DA9052_TOFFSET_REG;
+ msg.data = 0;
+ ret = da9052->read(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+ /* Calculate Junction temperature */
+ temp = (temp - msg.data);
+ *buf = temp;
+ return 0;
+err_ssc_comm:
+ da9052_unlock(da9052);
+ return -EIO;
+}
+EXPORT_SYMBOL(da9052_read_tjunc);
+
+int da9052_read_tbat_ich(struct da9052 *da9052, char *data, int channel_no)
+{
+ struct da9052_ssc_msg msg;
+ int ret;
+
+ /* Read TBAT conversion result */
+ switch (channel_no) {
+ case DA9052_ADC_TBAT:
+ msg.addr = DA9052_TBATRES_REG;
+ break;
+ case DA9052_ADC_ICH:
+ msg.addr = DA9052_ICHGAV_REG;
+ break;
+ default:
+ return -EINVAL;
+ }
+ msg.data = 0;
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+ *data = msg.data;
+ printk(KERN_INFO"msg.data 1= %d\n", msg.data);
+ msg.data = 28;
+ da9052_lock(da9052);
+ ret = da9052->write(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+ printk(KERN_INFO"msg.data2 = %d\n", msg.data);
+ msg.data = 0;
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+ printk(KERN_INFO"msg.data3 = %d\n", msg.data);
+ return 0;
+
+err_ssc_comm:
+ da9052_unlock(da9052);
+ return ret;
+}
+EXPORT_SYMBOL(da9052_read_tbat_ich);
+
+static int da9052_start_adc(struct da9052 *da9052, unsigned channel)
+{
+ struct da9052_ssc_msg msg;
+ int ret;
+
+ msg.addr = DA9052_ADCCONT_REG;
+ msg.data = 0;
+
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret != 0)
+ goto err_ssc_comm;
+
+ if (channel == DA9052_ADC_VDDOUT)
+ msg.data = (msg.data | DA9052_ADCCONT_AUTOVDDEN);
+ else if (channel == DA9052_ADC_ADCIN4)
+ msg.data = (msg.data | DA9052_ADCCONT_AUTOAD4EN);
+ else if (channel == DA9052_ADC_ADCIN5)
+ msg.data = (msg.data | DA9052_ADCCONT_AUTOAD5EN);
+ else if (channel == DA9052_ADC_ADCIN6)
+ msg.data = (msg.data | DA9052_ADCCONT_AUTOAD6EN);
+ else
+ return -EINVAL;
+
+ ret = da9052->write(da9052, &msg);
+ if (ret != 0)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+ return 0;
+
+err_ssc_comm:
+ da9052_unlock(da9052);
+ return -EIO;
+}
+
+static int da9052_stop_adc(struct da9052 *da9052, unsigned channel)
+{
+ int ret;
+ struct da9052_ssc_msg msg;
+
+ msg.addr = DA9052_ADCCONT_REG;
+ msg.data = 0;
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret != 0)
+ goto err_ssc_comm;
+
+ if (channel == DA9052_ADC_VDDOUT)
+ msg.data = (msg.data & ~(DA9052_ADCCONT_AUTOVDDEN));
+ else if (channel == DA9052_ADC_ADCIN4)
+ msg.data = (msg.data & ~(DA9052_ADCCONT_AUTOAD4EN));
+ else if (channel == DA9052_ADC_ADCIN5)
+ msg.data = (msg.data & ~(DA9052_ADCCONT_AUTOAD5EN));
+ else if (channel == DA9052_ADC_ADCIN6)
+ msg.data = (msg.data & ~(DA9052_ADCCONT_AUTOAD6EN));
+ else
+ return -EINVAL;
+
+ ret = da9052->write(da9052, &msg);
+ if (ret != 0)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+
+ return 0;
+err_ssc_comm:
+ da9052_unlock(da9052);
+ return -EIO;
+}
+
+static ssize_t da9052_adc_read_start_stop(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+ struct da9052_ssc_msg msg;
+ int channel = to_sensor_dev_attr(devattr)->index;
+ int ret;
+
+ ret = da9052_start_adc(priv->da9052, channel);
+ if (ret < 0)
+ return ret;
+
+ /* Read the ADC converted value */
+ switch (channel) {
+ case DA9052_ADC_VDDOUT:
+ msg.addr = DA9052_VDDRES_REG;
+ break;
+#if (DA9052_ADC_CONF_ADC4 == 1)
+ case DA9052_ADC_ADCIN4:
+ msg.addr = DA9052_ADCIN4RES_REG;
+ break;
+#endif
+#if (DA9052_ADC_CONF_ADC5 == 1)
+ case DA9052_ADC_ADCIN5:
+ msg.addr = DA9052_ADCIN5RES_REG;
+ break;
+#endif
+#if (DA9052_ADC_CONF_ADC6 == 1)
+ case DA9052_ADC_ADCIN6:
+ msg.addr = DA9052_ADCIN6RES_REG;
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+ msg.data = 0;
+ da9052_lock(priv->da9052);
+ ret = priv->da9052->read(priv->da9052, &msg);
+ if (ret != 0)
+ goto err_ssc_comm;
+ da9052_unlock(priv->da9052);
+
+ ret = da9052_stop_adc(priv->da9052, channel);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%u\n", msg.data);
+
+err_ssc_comm:
+ da9052_unlock(priv->da9052);
+ return ret;
+}
+
+static ssize_t da9052_adc_read_ich(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = da9052_read_tbat_ich(priv->da9052, buf, DA9052_ADC_ICH);
+ if (ret < 0)
+ return ret;
+ return sprintf(buf, "%u\n", *buf);
+}
+
+static ssize_t da9052_adc_read_tbat(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = da9052_read_tbat_ich(priv->da9052, buf, DA9052_ADC_TBAT);
+ if (ret < 0)
+ return ret;
+ return sprintf(buf, "%u\n", *buf);
+}
+
+static ssize_t da9052_adc_read_vbat(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+ s32 ret;
+
+ ret = da9052_manual_read(priv->da9052, DA9052_ADC_VBAT);
+ if (ret < 0)
+ return ret;
+ return sprintf(buf, "%u\n", ret);
+}
+
+static ssize_t da9052_adc_read_tjunc(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+ int ret;
+ ret = da9052_read_tjunc(priv->da9052, buf);
+ if (ret < 0)
+ return ret;
+ return sprintf(buf, "%u\n", *buf);
+}
+
+static ssize_t da9052_adc_read_vbbat(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+ s32 ret;
+
+ ret = da9052_manual_read(priv->da9052, DA9052_ADC_VBBAT);
+ if (ret < 0)
+ return ret;
+ return sprintf(buf, "%u\n", ret);
+}
+
+static int da9052_adc_hw_init(struct da9052 *da9052)
+{
+ struct da9052_ssc_msg msg;
+ int ret;
+
+ /* ADC channel 4 and 5 are by default enabled */
+#if (DA9052_ADC_CONF_ADC4 == 1)
+ msg.addr = DA9052_GPIO0001_REG;
+ msg.data = 0;
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+
+ msg.data = (msg.data & ~(DA9052_GPIO0001_GPIO0PIN));
+ ret = da9052->write(da9052, &msg);
+ if (ret != 0)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+#endif
+
+#if (DA9052_ADC_CONF_ADC5 == 1)
+ msg.addr = DA9052_GPIO0001_REG;
+ msg.data = 0;
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+
+ msg.data = (msg.data & ~(DA9052_GPIO0001_GPIO0PIN));
+ ret = da9052->write(da9052, &msg);
+ if (ret != 0)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+#endif
+
+#if (DA9052_ADC_CONF_ADC6 == 1)
+ msg.addr = DA9052_GPIO0203_REG;
+ msg.data = 0;
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret)
+ goto err_ssc_comm;
+
+ msg.data = (msg.data & ~(DA9052_GPIO0203_GPIO2PIN));
+ ret = da9052->write(da9052, &msg);
+ if (ret != 0)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+#endif
+#if 0
+ /* By default configure the Measurement sequence interval to 10ms */
+ msg.addr = DA9052_ADCCONT_REG;
+ msg.data = 0;
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
+ if (ret != 0)
+ goto err_ssc_comm;
+
+ /* Set the ADC MODE bit for 10msec sampling timer */
+ msg.data = (msg.data & ~(DA9052_ADCCONT_ADCMODE));
+ ret = da9052->write(da9052, &msg);
+ if (ret != 0)
+ goto err_ssc_comm;
+ da9052_unlock(da9052);
+#endif
+ return 0;
+err_ssc_comm:
+ da9052_unlock(da9052);
+ return -EIO;
+}
+
+static ssize_t da9052_adc_show_name(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return sprintf(buf, "da9052-adc\n");
+}
+
+static ssize_t show_label(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int channel = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%s\n", input_names[channel]);
+}
+#define DA9052_ADC_CHANNELS(id, name) \
+ static SENSOR_DEVICE_ATTR(in##id##_label, S_IRUGO, show_label, \
+ NULL, name)
+
+DA9052_ADC_CHANNELS(0, DA9052_ADC_VDDOUT);
+DA9052_ADC_CHANNELS(1, DA9052_ADC_ICH);
+DA9052_ADC_CHANNELS(2, DA9052_ADC_TBAT);
+DA9052_ADC_CHANNELS(3, DA9052_ADC_VBAT);
+#if (DA9052_ADC_CONF_ADC4 == 1)
+DA9052_ADC_CHANNELS(4, DA9052_ADC_ADCIN4);
+#endif
+#if (DA9052_ADC_CONF_ADC5 == 1)
+DA9052_ADC_CHANNELS(5, DA9052_ADC_ADCIN5);
+#endif
+#if (DA9052_ADC_CONF_ADC6 == 1)
+DA9052_ADC_CHANNELS(6, DA9052_ADC_ADCIN6);
+#endif
+DA9052_ADC_CHANNELS(7, DA9052_ADC_TSI);
+DA9052_ADC_CHANNELS(8, DA9052_ADC_TJUNC);
+DA9052_ADC_CHANNELS(9, DA9052_ADC_VBBAT);
+
+
+static DEVICE_ATTR(name, S_IRUGO, da9052_adc_show_name, NULL);
+static SENSOR_DEVICE_ATTR(read_vddout, S_IRUGO,
+ da9052_adc_read_start_stop, NULL,
+ DA9052_ADC_VDDOUT);
+static SENSOR_DEVICE_ATTR(read_ich, S_IRUGO, da9052_adc_read_ich, NULL,
+ DA9052_ADC_ICH);
+static SENSOR_DEVICE_ATTR(read_tbat, S_IRUGO, da9052_adc_read_tbat, NULL,
+ DA9052_ADC_TBAT);
+static SENSOR_DEVICE_ATTR(read_vbat, S_IRUGO, da9052_adc_read_vbat, NULL,
+ DA9052_ADC_VBAT);
+#if (DA9052_ADC_CONF_ADC4 == 1)
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, da9052_adc_read_start_stop, NULL,
+ DA9052_ADC_ADCIN4);
+#endif
+#if (DA9052_ADC_CONF_ADC5 == 1)
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, da9052_adc_read_start_stop, NULL,
+ DA9052_ADC_ADCIN5);
+#endif
+#if (DA9052_ADC_CONF_ADC6 == 1)
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, da9052_adc_read_start_stop, NULL,
+ DA9052_ADC_ADCIN6);
+#endif
+static SENSOR_DEVICE_ATTR(read_tjunc, S_IRUGO, da9052_adc_read_tjunc, NULL,
+ DA9052_ADC_TJUNC);
+static SENSOR_DEVICE_ATTR(read_vbbat, S_IRUGO, da9052_adc_read_vbbat, NULL,
+ DA9052_ADC_VBBAT);
+
+static struct attribute *da9052_attr[] = {
+ &dev_attr_name.attr,
+ &sensor_dev_attr_read_vddout.dev_attr.attr,
+ &sensor_dev_attr_in0_label.dev_attr.attr,
+ &sensor_dev_attr_read_ich.dev_attr.attr,
+ &sensor_dev_attr_in1_label.dev_attr.attr,
+ &sensor_dev_attr_read_tbat.dev_attr.attr,
+ &sensor_dev_attr_in2_label.dev_attr.attr,
+ &sensor_dev_attr_read_vbat.dev_attr.attr,
+ &sensor_dev_attr_in3_label.dev_attr.attr,
+#if (DA9052_ADC_CONF_ADC4 == 1)
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_label.dev_attr.attr,
+#endif
+#if (DA9052_ADC_CONF_ADC5 == 1)
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_label.dev_attr.attr,
+#endif
+#if (DA9052_ADC_CONF_ADC6 == 1)
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_label.dev_attr.attr,
+#endif
+ &sensor_dev_attr_in7_label.dev_attr.attr,
+ &sensor_dev_attr_read_tjunc.dev_attr.attr,
+ &sensor_dev_attr_in8_label.dev_attr.attr,
+ &sensor_dev_attr_read_vbbat.dev_attr.attr,
+ &sensor_dev_attr_in9_label.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group da9052_group = {
+ .attrs = da9052_attr,
+};
+
+static int __init da9052_adc_probe(struct platform_device *pdev)
+{
+ struct da9052_adc_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->da9052 = dev_get_drvdata(pdev->dev.parent);
+
+ platform_set_drvdata(pdev, priv);
+
+ /* Register sysfs hooks */
+ ret = sysfs_create_group(&pdev->dev.kobj, &da9052_group);
+ if (ret)
+ goto out_err_create1;
+
+ priv->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(priv->hwmon_dev)) {
+ ret = PTR_ERR(priv->hwmon_dev);
+ goto out_err_create2;
+ }
+ /* Initializes the hardware for ADC module */
+ da9052_adc_hw_init(priv->da9052);
+
+ /* Initialize mutex required for ADC Manual read */
+ mutex_init(&priv->da9052->manconv_lock);
+
+ return 0;
+
+out_err_create2:
+ sysfs_remove_group(&pdev->dev.kobj, &da9052_group);
+out_err_create1:
+ platform_set_drvdata(pdev, NULL);
+ kfree(priv);
+
+ return ret;
+}
+
+static int __devexit da9052_adc_remove(struct platform_device *pdev)
+{
+ struct da9052_adc_priv *priv = platform_get_drvdata(pdev);
+
+ mutex_destroy(&priv->da9052->manconv_lock);
+
+ hwmon_device_unregister(priv->hwmon_dev);
+
+ sysfs_remove_group(&pdev->dev.kobj, &da9052_group);
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(priv);
+
+ return 0;
+}
+
+static struct platform_driver da9052_adc_driver = {
+ .remove = __devexit_p(da9052_adc_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init da9052_adc_init(void)
+{
+ return platform_driver_probe(&da9052_adc_driver, da9052_adc_probe);
+}
+module_init(da9052_adc_init);
+
+static void __exit da9052_adc_exit(void)
+{
+ platform_driver_unregister(&da9052_adc_driver);
+}
+module_exit(da9052_adc_exit);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>")
+MODULE_DESCRIPTION("DA9052 ADC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/hwmon/isl29003.c b/drivers/hwmon/isl29003.c
new file mode 100644
index 000000000000..18c9947b3cd8
--- /dev/null
+++ b/drivers/hwmon/isl29003.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file drivers/hwmon/isl29003.c
+ *
+ * @brief ISL29003 light sensor Driver
+ *
+ * @ingroup
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/fsl_devices.h>
+#include <linux/slab.h>
+
+enum isl29003_width {
+ ISL29003_WIDTH_16 = 0,
+ ISL29003_WIDTH_12,
+ ISL29003_WIDTH_8,
+ ISL29003_WIDTH_4,
+};
+
+enum isl29003_gain {
+ ISL29003_GAIN_1000 = 0,
+ ISL29003_GAIN_4000,
+ ISL29003_GAIN_16000,
+ ISL29003_GAIN_64000,
+};
+
+enum isl29003_mode {
+ ISL29003_MODE_DIODE1 = 0,
+ ISL29003_MODE_DIODE2,
+ ISL29003_MODE_DIODE1_2,
+};
+
+struct isl29003_param {
+ enum isl29003_width width;
+ enum isl29003_gain gain;
+ enum isl29003_mode mode;
+};
+
+/* bit definition for ISL29003_CMD reg */
+#define ENABLE 7
+#define ADCPD 6
+#define TIMEING_MODE 5
+#define MODE 2
+#define WIDTH 0
+
+/* bit definition for ISL29003_CTRL reg */
+#define INT_FLAG 5
+#define GAIN 2
+#define INT_PERSIST 0
+
+enum isl29003_reg {
+ ISL29003_CMD = 0,
+ ISL29003_CTRL,
+ ISL29003_THRS_HI,
+ ISL29003_THRS_LO,
+ ISL29003_LSB_S,
+ ISL29003_MSB_S,
+ ISL29003_LSB_T,
+ ISL29003_MSB_T,
+ ISL29003_SYNC_IIC = 0x80,
+ ISL29003_CLAR_INT = 0x40
+};
+
+/* default configure for ISL29003 */
+#define ISL29003_WIDTH_DEFAULT ISL29003_WIDTH_16
+#define ISL29003_GAIN_DEFAULT ISL29003_GAIN_16000
+#define ISL29003_MODE_DEFAULT ISL29003_MODE_DIODE1
+
+/* range table for different GAIN settings */
+int range[4] = { 973, 3892, 15568, 62272 };
+
+/* width table for different WIDTH settings */
+int width[4] = { 16, 1, 256, 16 };
+
+struct isl29003_data {
+ struct i2c_client *client;
+ struct device *hwmon_dev;
+ struct regulator *vdd_reg;
+ struct isl29003_param param;
+ int lux_coeff;
+ unsigned char enable;
+};
+
+static struct i2c_client *isl29003_client;
+
+/*!
+ * This function do the isl29003 register read.
+ */
+int isl29003_read(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+/*!
+ * This function do the isl29003 register write.
+ */
+int isl29003_write(struct i2c_client *client, u8 reg, char value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/*!
+ * This function do the isl29003 config and enable.
+ */
+static int isl29003_on(void)
+{
+ unsigned char cmd;
+ int err = 0;
+ struct mxc_lightsensor_platform_data *ls_data;
+ struct isl29003_data *data = i2c_get_clientdata(isl29003_client);
+
+ if (data->enable)
+ goto exit;
+
+ ls_data = (struct mxc_lightsensor_platform_data *)
+ (isl29003_client->dev).platform_data;
+
+ /* coeff=range*100k/rext/2^n */
+ data->lux_coeff = range[data->param.gain] * 100 /
+ ls_data->rext / width[data->param.width];
+
+ if (data->vdd_reg)
+ regulator_enable(data->vdd_reg);
+ msleep(100);
+
+ cmd = data->param.gain << GAIN;
+ if (isl29003_write(isl29003_client, ISL29003_CTRL, cmd)) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ cmd = (data->param.width << WIDTH) | (data->param.mode << MODE) |
+ (1 << ENABLE);
+ if (isl29003_write(isl29003_client, ISL29003_CMD, cmd)) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ data->enable = 1;
+
+ pr_info("isl29003 on\n");
+ return 0;
+exit:
+ return err;
+}
+
+/*!
+ * This function shut down the isl29003.
+ */
+static int isl29003_off(void)
+{
+ struct isl29003_data *data = i2c_get_clientdata(isl29003_client);
+ int cmd;
+
+ if (!data->enable)
+ return 0;
+
+ cmd = isl29003_read(isl29003_client, ISL29003_CMD);
+ if (cmd < 0)
+ return -ENODEV;
+
+ cmd = ((cmd | (1 << ADCPD)) & (~(1 << ENABLE)));
+ if (isl29003_write(isl29003_client, ISL29003_CMD, (char)cmd))
+ return -ENODEV;
+
+ if (data->vdd_reg)
+ regulator_disable(data->vdd_reg);
+
+ data->enable = 0;
+
+ pr_info("isl29003 off\n");
+ return 0;
+}
+
+/*!
+ * This function read the isl29003 lux registers and convert them to the lux
+ * value.
+ *
+ * @output buffer this param holds the lux value, when =-1, read fail
+ *
+ * @return 0
+ */
+static int isl29003_read_lux(void)
+{
+ int d;
+ int lux;
+ struct isl29003_data *data = i2c_get_clientdata(isl29003_client);
+
+ d = isl29003_read(isl29003_client, ISL29003_MSB_S);
+ if (d < 0)
+ goto err;
+
+ lux = d;
+ d = isl29003_read(isl29003_client, ISL29003_LSB_S);
+ if (d < 0)
+ goto err;
+
+ lux = (lux << 8) + d;
+
+ if (data->param.width < ISL29003_WIDTH_8)
+ lux = (data->lux_coeff * lux) >> 12;
+ else
+ lux = data->lux_coeff * lux;
+
+ return lux;
+err:
+ return -1;
+}
+
+static ssize_t ls_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *endp;
+ int enable = simple_strtoul(buf, &endp, 0);
+ size_t size = endp - buf;
+
+ if (*endp && isspace(*endp))
+ size++;
+ if (size != count)
+ return -EINVAL;
+
+ if (enable == 1) {
+ if (isl29003_on())
+ pr_info("device open fail\n");
+ }
+ if (enable == 0) {
+ if (isl29003_off())
+ pr_info("device powerdown fail\n");
+ }
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(enable, S_IWUGO, NULL, ls_enable, 0);
+
+static ssize_t show_lux(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", isl29003_read_lux());
+}
+
+static SENSOR_DEVICE_ATTR(lux, S_IRUGO, show_lux, NULL, 0);
+
+static int isl29003_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ int err = 0;
+ struct isl29003_data *data;
+ struct regulator *vdd_reg;
+ struct mxc_lightsensor_platform_data *ls_data;
+
+ ls_data = (struct mxc_lightsensor_platform_data *)
+ (client->dev).platform_data;
+
+ if (ls_data && ls_data->vdd_reg)
+ vdd_reg = regulator_get(&client->dev, ls_data->vdd_reg);
+ else
+ vdd_reg = NULL;
+
+ /* check the existence of the device */
+ if (vdd_reg)
+ regulator_enable(vdd_reg);
+ msleep(100);
+
+ if (isl29003_write(client, ISL29003_CMD, 0))
+ err = -ENODEV;
+
+ if (!err)
+ if (isl29003_read(client, ISL29003_CMD))
+ err = -ENODEV;
+
+ if (vdd_reg)
+ regulator_disable(vdd_reg);
+ if (err < 0)
+ goto exit1;
+
+ isl29003_client = client;
+ data = kzalloc(sizeof(struct isl29003_data), GFP_KERNEL);
+ if (data == NULL) {
+ err = -ENOMEM;
+ goto exit1;
+ }
+
+ i2c_set_clientdata(client, data);
+ data->client = client;
+
+ data->param.width = ISL29003_WIDTH_DEFAULT;
+ data->param.gain = ISL29003_GAIN_DEFAULT;
+ data->param.mode = ISL29003_MODE_DEFAULT;
+
+ data->enable = 0;
+
+ err = device_create_file(&client->dev,
+ &sensor_dev_attr_enable.dev_attr);
+ if (err)
+ goto exit2;
+
+ err = device_create_file(&client->dev, &sensor_dev_attr_lux.dev_attr);
+ if (err)
+ goto exit_remove1;
+
+ /* Register sysfs hooks */
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove2;
+ }
+
+ data->vdd_reg = vdd_reg;
+ return 0;
+
+exit_remove2:
+ device_remove_file(&client->dev, &sensor_dev_attr_lux.dev_attr);
+exit_remove1:
+ device_remove_file(&client->dev, &sensor_dev_attr_enable.dev_attr);
+exit2:
+ kfree(data);
+exit1:
+ if (vdd_reg) {
+ regulator_put(vdd_reg);
+ vdd_reg = NULL;
+ }
+ isl29003_client = NULL;
+ return err;
+}
+
+static int isl29003_i2c_remove(struct i2c_client *client)
+{
+ struct isl29003_data *data = i2c_get_clientdata(client);
+
+ if (data->vdd_reg) {
+ regulator_put(data->vdd_reg);
+ data->vdd_reg = NULL;
+ }
+ hwmon_device_unregister(data->hwmon_dev);
+ device_remove_file(&client->dev, &sensor_dev_attr_enable.dev_attr);
+ device_remove_file(&client->dev, &sensor_dev_attr_lux.dev_attr);
+ kfree(data);
+ return 0;
+}
+
+static int isl29003_suspend(struct i2c_client *client, pm_message_t message)
+{
+ int cmd;
+
+ struct isl29003_data *data = i2c_get_clientdata(client);
+
+ if (!data->enable)
+ goto exit;
+
+ cmd = isl29003_read(client, ISL29003_CMD);
+ if (cmd < 0)
+ goto err;
+
+ cmd = (cmd | (1 << ADCPD));
+ if (isl29003_write(client, ISL29003_CMD, (char)cmd))
+ goto err;
+exit:
+ return 0;
+err:
+ return -ENODEV;
+}
+
+static int isl29003_resume(struct i2c_client *client)
+{
+ int cmd;
+
+ struct isl29003_data *data = i2c_get_clientdata(client);
+
+ if (!data->enable)
+ goto exit;
+
+ cmd = isl29003_read(client, ISL29003_CMD);
+ if (cmd < 0)
+ goto err;
+
+ cmd = (cmd & (~(1 << ADCPD)));
+ if (isl29003_write(client, ISL29003_CMD, (char)cmd))
+ goto err;
+exit:
+ return 0;
+err:
+ return -ENODEV;
+}
+
+static const struct i2c_device_id isl29003_id[] = {
+ {"isl29003", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, isl29003_id);
+
+static struct i2c_driver isl29003_driver = {
+ .driver = {
+ .name = "isl29003",
+ },
+ .probe = isl29003_i2c_probe,
+ .remove = isl29003_i2c_remove,
+ .suspend = isl29003_suspend,
+ .resume = isl29003_resume,
+ .id_table = isl29003_id,
+};
+
+static int __init isl29003_init(void)
+{
+ return i2c_add_driver(&isl29003_driver);;
+}
+
+static void __exit isl29003_cleanup(void)
+{
+ i2c_del_driver(&isl29003_driver);
+}
+
+module_init(isl29003_init);
+module_exit(isl29003_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("ISL29003 light sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max17135-hwmon.c b/drivers/hwmon/max17135-hwmon.c
new file mode 100644
index 000000000000..8aa9aadbd44a
--- /dev/null
+++ b/drivers/hwmon/max17135-hwmon.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, 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
+ *
+ */
+/*
+ * max17135.c
+ *
+ * Based on the MAX1619 driver.
+ * Copyright (C) 2003-2004 Alexey Fisher <fishor@mail.ru>
+ * Jean Delvare <khali@linux-fr.org>
+ *
+ * The MAX17135 is a sensor chip made by Maxim.
+ * It reports up to two temperatures (its own plus up to
+ * one external one).
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max17135.h>
+
+/*
+ * Conversions
+ */
+static int temp_from_reg(int val)
+{
+ return val >> 8;
+}
+
+/*
+ * Functions declaration
+ */
+static int max17135_sensor_probe(struct platform_device *pdev);
+static int max17135_sensor_remove(struct platform_device *pdev);
+
+/*
+ * Driver data (common to all clients)
+ */
+static struct platform_driver max17135_sensor_driver = {
+ .probe = max17135_sensor_probe,
+ .remove = max17135_sensor_remove,
+ .driver = {
+ .name = "max17135_sensor",
+ },
+};
+
+
+/*
+ * Client data (each client gets its own)
+ */
+struct max17135_data {
+ struct device *hwmon_dev;
+};
+
+/*
+ * Sysfs stuff
+ */
+static ssize_t show_temp_input1(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int reg_val;
+ max17135_reg_read(REG_MAX17135_INT_TEMP, &reg_val);
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp_from_reg(reg_val));
+}
+
+static ssize_t show_temp_input2(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int reg_val;
+ max17135_reg_read(REG_MAX17135_EXT_TEMP, &reg_val);
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp_from_reg(reg_val));
+}
+
+show_temp(temp_input1);
+show_temp(temp_input2);
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
+static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL);
+
+static struct attribute *max17135_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_input.attr,
+ NULL
+};
+
+static const struct attribute_group max17135_group = {
+ .attrs = max17135_attributes,
+};
+
+/*
+ * Real code
+ */
+static int max17135_sensor_probe(struct platform_device *pdev)
+{
+ struct max17135_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct max17135_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&pdev->dev.kobj, &max17135_group);
+ if (err)
+ goto exit_free;
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove_files;
+ }
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+exit_remove_files:
+ sysfs_remove_group(&pdev->dev.kobj, &max17135_group);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int max17135_sensor_remove(struct platform_device *pdev)
+{
+ struct max17135_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &max17135_group);
+
+ kfree(data);
+ return 0;
+}
+
+static int __init sensors_max17135_init(void)
+{
+ return platform_driver_register(&max17135_sensor_driver);
+}
+module_init(sensors_max17135_init);
+
+static void __exit sensors_max17135_exit(void)
+{
+ platform_driver_unregister(&max17135_sensor_driver);
+}
+module_exit(sensors_max17135_exit);
+
+MODULE_DESCRIPTION("MAX17135 sensor driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hwmon/mxc_mma7450.c b/drivers/hwmon/mxc_mma7450.c
new file mode 100644
index 000000000000..fa1dd41267eb
--- /dev/null
+++ b/drivers/hwmon/mxc_mma7450.c
@@ -0,0 +1,788 @@
+/*
+ * linux/drivers/hwmon/mma7450.c
+ *
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*include file*/
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/input-polldev.h>
+#include <linux/hwmon.h>
+#include <linux/regulator/consumer.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/fsl_devices.h>
+
+/*macro define*/
+#define MMA7450_I2C_ADDR 0x1D
+#define DEVICE_NAME "mma7450"
+#define POLL_INTERVAL 100
+#define DEBUG
+
+#define INPUT_FUZZ 4
+#define INPUT_FLAT 4
+
+enum {
+ REG_XOUTL = 0x00,
+ REG_XOUTH,
+ REG_YOUTL,
+ REG_YOUTH,
+ REG_ZOUTL,
+ REG_ZOUTH,
+ REG_XOUT8,
+ REG_YOUT8,
+ REG_ZOUT8,
+ REG_STATUS,
+ REG_DETSRC,
+ REG_TOUT,
+ REG_RESERVED_0,
+ REG_I2CAD,
+ REG_USRINF,
+ REG_WHOAMI,
+ REG_XOFFL,
+ REG_XOFFH,
+ REG_YOFFL,
+ REG_YOFFH,
+ REG_ZOFFL,
+ REG_ZOFFH,
+ REG_MCTL,
+ REG_INTRST,
+ REG_CTL1,
+ REG_CTL2,
+ REG_LDTH,
+ REG_PDTH,
+ REG_PD,
+ REG_LT,
+ REG_TW,
+ REG_REVERVED_1,
+};
+
+enum {
+ MOD_STANDBY = 0,
+ MOD_MEASURE,
+ MOD_LEVEL_D,
+ MOD_PULSE_D,
+};
+
+enum {
+ INT_1L_2P = 0,
+ INT_1P_2L,
+ INT_1SP_2P,
+};
+
+struct mma7450_status {
+ u8 mod;
+ u8 ctl1;
+ u8 ctl2;
+};
+
+/*forward declear*/
+static ssize_t mma7450_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t mma7450_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count);
+static int mma7450_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int mma7450_remove(struct i2c_client *client);
+static int mma7450_suspend(struct i2c_client *client, pm_message_t state);
+static int mma7450_resume(struct i2c_client *client);
+static void mma_bh_handler(struct work_struct *work);
+
+/*definition*/
+static struct regulator *reg_dvdd_io;
+static struct regulator *reg_avdd;
+static struct i2c_client *mma7450_client;
+static struct device *hwmon_dev;
+static struct input_polled_dev *mma7450_idev;
+static struct mxc_mma7450_platform_data *plat_data;
+static u8 mma7450_mode;
+static struct device_attribute mma7450_dev_attr = {
+ .attr = {
+ .name = "mma7450_ctl",
+ .mode = S_IRUSR | S_IWUSR,
+ },
+ .show = mma7450_show,
+ .store = mma7450_store,
+};
+
+static const struct i2c_device_id mma7450_id[] = {
+ {"mma7450", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, mma7450_id);
+
+static struct i2c_driver i2c_mma7450_driver = {
+ .driver = {
+ .name = "mma7450",
+ },
+ .probe = mma7450_probe,
+ .remove = mma7450_remove,
+ .suspend = mma7450_suspend,
+ .resume = mma7450_resume,
+ .id_table = mma7450_id,
+};
+
+static struct mma7450_status mma_status = {
+ .mod = 0,
+ .ctl1 = 0,
+ .ctl2 = 0,
+};
+
+DECLARE_WORK(mma_work, mma_bh_handler);
+
+#ifdef DEBUG
+enum {
+ MMA_REG_R = 0,
+ MMA_REG_W,
+ MMA_SET_MOD,
+ MMA_SET_L_THR,
+ MMA_SET_P_THR,
+ MMA_SET_INTP,
+ MMA_SET_INTB,
+ MMA_SET_G,
+ MMA_I2C_EABLE,
+ MMA_OFF_X,
+ MMA_OFF_Y,
+ MMA_OFF_Z,
+ MMA_SELF_TEST,
+ MMA_SET_LDPL,
+ MMA_SET_PDPL,
+ MMA_SET_PDV,
+ MMA_SET_LTV,
+ MMA_SET_TW,
+ MMA_CMD_MAX
+};
+
+static char *command[MMA_CMD_MAX] = {
+ [MMA_REG_R] = "readreg",
+ [MMA_REG_W] = "writereg",
+ [MMA_SET_MOD] = "setmod",
+ [MMA_SET_L_THR] = "setlt",
+ [MMA_SET_P_THR] = "setpt",
+ [MMA_SET_INTP] = "setintp",
+ [MMA_SET_INTB] = "setintb",
+ [MMA_SET_G] = "setg",
+ [MMA_I2C_EABLE] = "setie",
+ [MMA_OFF_X] = "setxo",
+ [MMA_OFF_Y] = "setyo",
+ [MMA_OFF_Z] = "setzo",
+ [MMA_SELF_TEST] = "selft",
+ [MMA_SET_LDPL] = "setldp",
+ [MMA_SET_PDPL] = "setpdp",
+ [MMA_SET_PDV] = "setpdv",
+ [MMA_SET_LTV] = "setltv",
+ [MMA_SET_TW] = "settw",
+};
+
+static void set_mod(u8 mode)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(mma7450_client, REG_MCTL);
+ /* shall I test the ret value? */
+ ret = (ret & ~0x3) | (mode & 0x3);
+ mma_status.mod = ret;
+ i2c_smbus_write_byte_data(mma7450_client, REG_MCTL, ret);
+}
+
+static void set_level_thr(u8 lth)
+{
+ i2c_smbus_write_byte_data(mma7450_client, REG_LDTH, lth);
+}
+
+static void set_pulse_thr(u8 pth)
+{
+ i2c_smbus_write_byte_data(mma7450_client, REG_PDTH, pth);
+}
+
+static void set_int_pin(u8 pin)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(mma7450_client, REG_CTL1);
+ ret = (ret & ~0x1) | (pin & 0x1);
+ mma_status.ctl1 = ret;
+ i2c_smbus_write_byte_data(mma7450_client, REG_CTL1, ret);
+}
+
+static void set_int_bit(u8 bit)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(mma7450_client, REG_CTL1);
+ ret = (ret & ~0x6) | ((bit << 1) & 0x6);
+ mma_status.ctl1 = ret;
+ i2c_smbus_write_byte_data(mma7450_client, REG_CTL1, ret);
+}
+
+static void set_g_level(u8 gl)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(mma7450_client, REG_MCTL);
+ ret = (ret & ~0xC) | ((gl << 2) & 0xC);
+ i2c_smbus_write_byte_data(mma7450_client, REG_MCTL, ret);
+}
+
+static void set_i2c_enable(u8 i2c_e)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(mma7450_client, REG_I2CAD);
+ ret = (ret & ~0x80) | ((i2c_e << 7) & 0x80);
+ i2c_smbus_write_byte_data(mma7450_client, REG_I2CAD, ret);
+}
+
+static void set_x_offset(u16 xo)
+{
+ u8 data;
+
+ data = (xo & 0xFF);
+ i2c_smbus_write_byte_data(mma7450_client, REG_XOFFL, data);
+ data = (xo & 0xFF00) >> 8;
+ i2c_smbus_write_byte_data(mma7450_client, REG_XOFFH, data);
+}
+
+static void set_y_offset(u16 yo)
+{
+ u8 data;
+
+ data = (yo & 0xFF);
+ i2c_smbus_write_byte_data(mma7450_client, REG_YOFFL, data);
+ data = (yo & 0xFF00) >> 8;
+ i2c_smbus_write_byte_data(mma7450_client, REG_YOFFH, data);
+}
+
+static void set_z_offset(u16 zo)
+{
+ u8 data;
+
+ data = (zo & 0xFF);
+ i2c_smbus_write_byte_data(mma7450_client, REG_ZOFFL, data);
+ data = (zo & 0xFF00) >> 8;
+ i2c_smbus_write_byte_data(mma7450_client, REG_ZOFFH, data);
+}
+
+static void selftest(u8 st)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(mma7450_client, REG_MCTL);
+ ret = (ret & ~0x10) | ((st << 4) & 0x10);
+ i2c_smbus_write_byte_data(mma7450_client, REG_MCTL, ret);
+}
+
+static void set_level_det_p(u8 ldp)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(mma7450_client, REG_CTL2);
+ ret = (ret & ~0x1) | ((ldp << 0) & 0x1);
+ mma_status.ctl2 = ret;
+ i2c_smbus_write_byte_data(mma7450_client, REG_CTL2, ret);
+}
+
+static void set_pulse_det_p(u8 pdp)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(mma7450_client, REG_CTL2);
+ ret = (ret & ~0x2) | ((pdp << 1) & 0x2);
+ mma_status.ctl2 = ret;
+ i2c_smbus_write_byte_data(mma7450_client, REG_CTL2, ret);
+}
+
+static void set_pulse_duration(u8 pd)
+{
+ i2c_smbus_write_byte_data(mma7450_client, REG_PD, pd);
+}
+
+static void set_latency_time(u8 lt)
+{
+ i2c_smbus_write_byte_data(mma7450_client, REG_LT, lt);
+}
+
+static void set_time_window(u8 tw)
+{
+ i2c_smbus_write_byte_data(mma7450_client, REG_TW, tw);
+}
+
+static void parse_arg(const char *arg, int *reg, int *value)
+{
+ const char *p;
+
+ for (p = arg;; p++) {
+ if (*p == ' ' || *p == '\0')
+ break;
+ }
+
+ p++;
+
+ *reg = simple_strtoul(arg, NULL, 16);
+ *value = simple_strtoul(p, NULL, 16);
+}
+
+static void cmd_read_reg(const char *arg)
+{
+ int reg, value, ret;
+
+ parse_arg(arg, &reg, &value);
+ ret = i2c_smbus_read_byte_data(mma7450_client, reg);
+ dev_info(&mma7450_client->dev, "read reg0x%x = %x\n", reg, ret);
+}
+
+static void cmd_write_reg(const char *arg)
+{
+ int reg, value, ret;
+
+ parse_arg(arg, &reg, &value);
+ ret = i2c_smbus_write_byte_data(mma7450_client, reg, value);
+ dev_info(&mma7450_client->dev, "write reg result %s\n",
+ ret ? "failed" : "success");
+}
+
+static int exec_command(const char *buf, size_t count)
+{
+ const char *p, *s;
+ const char *arg;
+ int i, value = 0;
+
+ for (p = buf;; p++) {
+ if (*p == ' ' || *p == '\0' || p - buf >= count)
+ break;
+ }
+ arg = p + 1;
+
+ for (i = MMA_REG_R; i < MMA_CMD_MAX; i++) {
+ s = command[i];
+ if (s && !strncmp(buf, s, p - buf)) {
+ dev_info(&mma7450_client->dev, "command %s\n", s);
+ goto mma_exec_command;
+ }
+ }
+
+ dev_err(&mma7450_client->dev, "command is not found\n");
+ return -1;
+
+ mma_exec_command:
+ if (i != MMA_REG_R && i != MMA_REG_W)
+ value = simple_strtoul(arg, NULL, 16);
+
+ switch (i) {
+ case MMA_REG_R:
+ cmd_read_reg(arg);
+ break;
+ case MMA_REG_W:
+ cmd_write_reg(arg);
+ break;
+ case MMA_SET_MOD:
+ set_mod(value);
+ break;
+ case MMA_SET_L_THR:
+ set_level_thr(value);
+ break;
+ case MMA_SET_P_THR:
+ set_pulse_thr(value);
+ break;
+ case MMA_SET_INTP:
+ set_int_pin(value);
+ break;
+ case MMA_SET_INTB:
+ set_int_bit(value);
+ break;
+ case MMA_SET_G:
+ set_g_level(value);
+ break;
+ case MMA_I2C_EABLE:
+ set_i2c_enable(value);
+ break;
+ case MMA_OFF_X:
+ set_x_offset(value);
+ break;
+ case MMA_OFF_Y:
+ set_y_offset(value);
+ break;
+ case MMA_OFF_Z:
+ set_z_offset(value);
+ break;
+ case MMA_SELF_TEST:
+ selftest(value);
+ break;
+ case MMA_SET_LDPL:
+ set_level_det_p(value);
+ break;
+ case MMA_SET_PDPL:
+ set_pulse_det_p(value);
+ break;
+ case MMA_SET_PDV:
+ set_pulse_duration(value);
+ break;
+ case MMA_SET_LTV:
+ set_latency_time(value);
+ break;
+ case MMA_SET_TW:
+ set_time_window(value);
+ break;
+ default:
+ dev_err(&mma7450_client->dev, "command is not found\n");
+ break;
+ }
+
+ return 0;
+}
+
+static ssize_t mma7450_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret, reg;
+
+ for (reg = REG_XOUTL; reg < REG_REVERVED_1; reg++) {
+ ret = i2c_smbus_read_byte_data(mma7450_client, reg);
+ dev_info(&mma7450_client->dev, "reg0x%02x:\t%03d\t0x%02x\n",
+ reg, (s8) ret, ret);
+ }
+
+ return 0;
+}
+
+static ssize_t mma7450_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ exec_command(buf, count);
+
+ return count;
+}
+
+#else
+
+static ssize_t mma7450_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static ssize_t mma7450_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ return count;
+}
+
+#endif
+
+static void report_abs(void)
+{
+ u8 status, mod = mma_status.mod;
+ s16 x, y, z;
+
+ status = i2c_smbus_read_byte_data(mma7450_client, REG_STATUS);
+ if (!(status & 0x01)) { /* data ready in measurement mode? */
+ return;
+ }
+ if ((mod & 0x0c) == 0) { /* 8g range */
+ x = 0xFF & i2c_smbus_read_byte_data(mma7450_client, REG_XOUTL);
+ x |= 0xFF00 &
+ (i2c_smbus_read_byte_data(mma7450_client, REG_XOUTH) << 8);
+ y = 0xFF & i2c_smbus_read_byte_data(mma7450_client, REG_YOUTL);
+ y |= 0xFF00 &
+ (i2c_smbus_read_byte_data(mma7450_client, REG_YOUTH) << 8);
+ z = 0xFF & i2c_smbus_read_byte_data(mma7450_client, REG_ZOUTL);
+ z |= 0xFF00 &
+ (i2c_smbus_read_byte_data(mma7450_client, REG_ZOUTH) << 8);
+ } else { /* 2g/4g range */
+ x = 0xFF & i2c_smbus_read_byte_data(mma7450_client, REG_XOUT8);
+ y = 0xFF & i2c_smbus_read_byte_data(mma7450_client, REG_YOUT8);
+ z = 0xFF & i2c_smbus_read_byte_data(mma7450_client, REG_ZOUT8);
+ }
+
+ status = i2c_smbus_read_byte_data(mma7450_client, REG_STATUS);
+ if (status & 0x02) { /* data is overwrite */
+ return;
+ }
+
+ /* convert signed 10bits to signed 16bits */
+ x = (short)(x << 6) >> 6;
+ y = (short)(y << 6) >> 6;
+ z = (short)(z << 6) >> 6;
+
+ input_report_abs(mma7450_idev->input, ABS_X, x);
+ input_report_abs(mma7450_idev->input, ABS_Y, y);
+ input_report_abs(mma7450_idev->input, ABS_Z, z);
+ input_sync(mma7450_idev->input);
+}
+
+static void mma_bh_handler(struct work_struct *work)
+{
+}
+
+static void mma7450_dev_poll(struct input_polled_dev *dev)
+{
+ report_abs();
+}
+
+static irqreturn_t mma7450_interrupt(int irq, void *dev_id)
+{
+ struct input_dev *input_dev = dev_id;
+ u8 int_bit, int_pin;
+
+ int_bit = mma_status.ctl1 & 0x6;
+ int_pin = mma_status.ctl1 & 0x1;
+
+ switch (mma_status.mod & 0x03) {
+ case 1:
+ /*only int1 report data ready int */
+ if (plat_data->int1 != irq)
+ goto error_bad_int;
+ schedule_work(&mma_work);
+ break;
+ case 2:
+ /* for level and pulse detection mode,
+ * choice tasklet to handle interrupt quickly.
+ * Currently, leave it doing nothing*/
+ if (plat_data->int1 == irq) {
+ if ((int_bit == 0) && (int_pin != 0))
+ goto error_bad_int;
+ if ((int_bit == 0x2) && (int_pin != 0x1))
+ goto error_bad_int;
+ if (int_bit == 0x4)
+ goto error_bad_int;
+ }
+ if (plat_data->int2 == irq) {
+ if ((int_bit == 0) && (int_pin != 0x1))
+ goto error_bad_int;
+ if ((int_bit == 0x2) && (int_pin != 0))
+ goto error_bad_int;
+ if (int_bit == 0x4)
+ goto error_bad_int;
+ }
+
+ dev_info(&input_dev->dev, "motion detected in level mod\n");
+
+ break;
+ case 3:
+ if (plat_data->int1 == irq) {
+ if ((int_bit == 0) && (int_pin != 0x1))
+ goto error_bad_int;
+ if ((int_bit == 0x2) && (int_pin != 0))
+ goto error_bad_int;
+ if ((int_bit == 0x4) && (int_pin != 0x1))
+ goto error_bad_int;
+ }
+ if (plat_data->int2 == irq) {
+ if ((int_bit == 0) && (int_pin != 0))
+ goto error_bad_int;
+ if ((int_bit == 0x2) && (int_pin != 0x1))
+ goto error_bad_int;
+ if ((int_bit == 0x4) && (int_pin != 0))
+ goto error_bad_int;
+ }
+
+ if (mma_status.ctl2 & 0x02)
+ dev_info(&input_dev->dev,
+ "freefall detected in pulse mod\n");
+ else
+ dev_info(&input_dev->dev,
+ "motion detected in pulse mod\n");
+
+ break;
+ case 0:
+ default:
+ break;
+ }
+ error_bad_int:
+ return IRQ_RETVAL(1);
+}
+
+static int mma7450_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct input_dev *idev;
+
+ plat_data =
+ (struct mxc_mma7450_platform_data *)client->dev.platform_data;
+ if (plat_data == NULL) {
+ dev_err(&client->dev, "lack of platform data!\n");
+ return -ENODEV;
+ }
+
+ /*enable power supply */
+ /*when to power on/off the power is to be considered later */
+ /*shall I check the return value */
+ reg_dvdd_io = regulator_get(&client->dev, plat_data->reg_dvdd_io);
+ if (reg_dvdd_io != ERR_PTR(-ENOENT))
+ regulator_enable(reg_dvdd_io);
+ else
+ return -EINVAL;
+
+ reg_avdd = regulator_get(&client->dev, plat_data->reg_avdd);
+ if (reg_avdd != ERR_PTR(-ENOENT))
+ regulator_enable(reg_avdd);
+ else {
+ regulator_put(reg_dvdd_io);
+ return -EINVAL;
+ }
+
+ /*bind the right device to the driver */
+ ret = i2c_smbus_read_byte_data(client, REG_I2CAD);
+ if (MMA7450_I2C_ADDR != (0x7F & ret)) { /*compare the address value */
+ dev_err(&client->dev,
+ "read chip ID 0x%x is not equal to 0x%x!\n", ret,
+ MMA7450_I2C_ADDR);
+ goto error_disable_power;
+ }
+ mma7450_client = client;
+
+ /*interrupt register */
+ /*when to register interrupt is to be considered later */
+
+ /*create device file in sysfs as user interface */
+ ret = device_create_file(&client->dev, &mma7450_dev_attr);
+ if (ret) {
+ dev_err(&client->dev, "create device file failed!\n");
+ goto error_disable_power;
+ }
+
+ /*register to hwmon device */
+ hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(hwmon_dev)) {
+ dev_err(&client->dev, "hwmon register failed!\n");
+ ret = PTR_ERR(hwmon_dev);
+ goto error_rm_dev_file;
+ }
+
+ /*input poll device register */
+ mma7450_idev = input_allocate_polled_device();
+ if (!mma7450_idev) {
+ dev_err(&client->dev, "alloc poll device failed!\n");
+ ret = -ENOMEM;
+ goto error_rm_hwmon_dev;
+ }
+ mma7450_idev->poll = mma7450_dev_poll;
+ mma7450_idev->poll_interval = POLL_INTERVAL;
+ idev = mma7450_idev->input;
+ idev->name = DEVICE_NAME;
+ idev->id.bustype = BUS_I2C;
+ idev->dev.parent = &client->dev;
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+
+ input_set_abs_params(idev, ABS_X, -512, 512, INPUT_FUZZ, INPUT_FLAT);
+ input_set_abs_params(idev, ABS_Y, -512, 512, INPUT_FUZZ, INPUT_FLAT);
+ input_set_abs_params(idev, ABS_Z, -512, 512, INPUT_FUZZ, INPUT_FLAT);
+ ret = input_register_polled_device(mma7450_idev);
+ if (ret) {
+ dev_err(&client->dev, "register poll device failed!\n");
+ goto error_free_poll_dev;
+ }
+
+ /* configure gpio as input for interrupt monitor */
+ plat_data->gpio_pin_get();
+
+ set_irq_type(plat_data->int1, IRQF_TRIGGER_RISING);
+ /* register interrupt handle */
+ ret = request_irq(plat_data->int1, mma7450_interrupt,
+ IRQF_TRIGGER_RISING, DEVICE_NAME, idev);
+
+ if (ret) {
+ dev_err(&client->dev, "request_irq(%d) returned error %d\n",
+ plat_data->int1, ret);
+ goto error_rm_poll_dev;
+ }
+
+ set_irq_type(plat_data->int2, IRQF_TRIGGER_RISING);
+ ret = request_irq(plat_data->int2, mma7450_interrupt,
+ IRQF_TRIGGER_RISING, DEVICE_NAME, idev);
+ if (ret) {
+ dev_err(&client->dev, "request_irq(%d) returned error %d\n",
+ plat_data->int2, ret);
+ goto error_free_irq1;
+ }
+
+ dev_info(&client->dev, "mma7450 device is probed successfully.\n");
+
+ set_mod(1);
+ return 0; /*what value shall be return */
+
+ /*error handle */
+ error_free_irq1:
+ free_irq(plat_data->int1, 0);
+ error_rm_poll_dev:
+ input_unregister_polled_device(mma7450_idev);
+ error_free_poll_dev:
+ input_free_polled_device(mma7450_idev);
+ error_rm_hwmon_dev:
+ hwmon_device_unregister(hwmon_dev);
+ error_rm_dev_file:
+ device_remove_file(&client->dev, &mma7450_dev_attr);
+ error_disable_power:
+ regulator_disable(reg_dvdd_io); /*shall I check the return value */
+ regulator_disable(reg_avdd);
+ regulator_put(reg_dvdd_io);
+ regulator_put(reg_avdd);
+
+ return ret;
+}
+
+static int mma7450_remove(struct i2c_client *client)
+{
+ free_irq(plat_data->int2, mma7450_idev->input);
+ free_irq(plat_data->int1, mma7450_idev->input);
+ plat_data->gpio_pin_put();
+ input_unregister_polled_device(mma7450_idev);
+ input_free_polled_device(mma7450_idev);
+ hwmon_device_unregister(hwmon_dev);
+ device_remove_file(&client->dev, &mma7450_dev_attr);
+ regulator_disable(reg_dvdd_io); /*shall I check the return value */
+ regulator_disable(reg_avdd);
+ regulator_put(reg_dvdd_io);
+ regulator_put(reg_avdd);
+ return 0;
+}
+
+static int mma7450_suspend(struct i2c_client *client, pm_message_t state)
+{
+ mma7450_mode = i2c_smbus_read_byte_data(mma7450_client, REG_MCTL);
+ i2c_smbus_write_byte_data(mma7450_client, REG_MCTL,
+ mma7450_mode & ~0x3);
+ return 0;
+}
+
+static int mma7450_resume(struct i2c_client *client)
+{
+ i2c_smbus_write_byte_data(mma7450_client, REG_MCTL, mma7450_mode);
+ return 0;
+}
+
+static int __init init_mma7450(void)
+{
+ /*register driver */
+ printk(KERN_INFO "add mma i2c driver\n");
+ return i2c_add_driver(&i2c_mma7450_driver);
+}
+
+static void __exit exit_mma7450(void)
+{
+ printk(KERN_INFO "del mma i2c driver.\n");
+ return i2c_del_driver(&i2c_mma7450_driver);
+}
+
+module_init(init_mma7450);
+module_exit(exit_mma7450);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MMA7450 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/mxc_mma8450.c b/drivers/hwmon/mxc_mma8450.c
new file mode 100644
index 000000000000..3d4c1ef1f4d9
--- /dev/null
+++ b/drivers/hwmon/mxc_mma8450.c
@@ -0,0 +1,390 @@
+/*
+ * mma8450.c - Linux kernel modules for 3-Axis Orientation/Motion
+ * Detection Sensor
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/input-polldev.h>
+
+/*
+ * Defines
+ */
+#define assert(expr)\
+ if (!(expr)) {\
+ printk(KERN_ERR "Assertion failed! %s,%d,%s,%s\n",\
+ __FILE__, __LINE__, __func__, #expr);\
+ }
+
+#define MMA8450_DRV_NAME "mma8450"
+#define MMA8450_I2C_ADDR 0x1C
+#define MMA8450_ID 0xC6
+#define MMA8450_STATUS 0x00
+#define MODE_CHANGE_DELAY_MS 100
+#define POLL_INTERVAL 100
+#define INPUT_FUZZ 32
+#define INPUT_FLAT 32
+
+/* register enum for mma8450 registers */
+enum {
+ MMA8450_STATUS1 = 0x00,
+ MMA8450_OUT_X8,
+ MMA8450_OUT_Y8,
+ MMA8450_OUT_Z8,
+
+ MMA8450_STATUS2,
+ MMA8450_OUT_X_LSB,
+ MMA8450_OUT_X_MSB,
+ MMA8450_OUT_Y_LSB,
+ MMA8450_OUT_Y_MSB,
+ MMA8450_OUT_Z_LSB,
+ MMA8450_OUT_Z_MSB,
+
+ MMA8450_STATUS3,
+ MMA8450_OUT_X_DELTA,
+ MMA8450_OUT_Y_DELTA,
+ MMA8450_OUT_Z_DELTA,
+
+ MMA8450_WHO_AM_I,
+
+ MMA8450_F_STATUS,
+ MMA8450_F_8DATA,
+ MMA8450_F_12DATA,
+ MMA8450_F_SETUP,
+
+ MMA8450_SYSMOD,
+ MMA8450_INT_SOURCE,
+ MMA8450_XYZ_DATA_CFG,
+ MMA8450_HP_FILTER_CUTOFF,
+
+ MMA8450_PL_STATUS,
+ MMA8450_PL_PRE_STATUS,
+ MMA8450_PL_CFG,
+ MMA8450_PL_COUNT,
+ MMA8450_PL_BF_ZCOMP,
+ MMA8450_PL_P_L_THS_REG1,
+ MMA8450_PL_P_L_THS_REG2,
+ MMA8450_PL_P_L_THS_REG3,
+ MMA8450_PL_L_P_THS_REG1,
+ MMA8450_PL_L_P_THS_REG2,
+ MMA8450_PL_L_P_THS_REG3,
+
+ MMA8450_FF_MT_CFG_1,
+ MMA8450_FF_MT_SRC_1,
+ MMA8450_FF_MT_THS_1,
+ MMA8450_FF_MT_COUNT_1,
+ MMA8450_FF_MT_CFG_2,
+ MMA8450_FF_MT_SRC_2,
+ MMA8450_FF_MT_THS_2,
+ MMA8450_FF_MT_COUNT_2,
+
+ MMA8450_TRANSIENT_CFG,
+ MMA8450_TRANSIENT_SRC,
+ MMA8450_TRANSIENT_THS,
+ MMA8450_TRANSIENT_COUNT,
+
+ MMA8450_PULSE_CFG,
+ MMA8450_PULSE_SRC,
+ MMA8450_PULSE_THSX,
+ MMA8450_PULSE_THSY,
+ MMA8450_PULSE_THSZ,
+ MMA8450_PULSE_TMLT,
+ MMA8450_PULSE_LTCY,
+ MMA8450_PULSE_WIND,
+
+ MMA8450_ASLP_COUNT,
+ MMA8450_CTRL_REG1,
+ MMA8450_CTRL_REG2,
+ MMA8450_CTRL_REG3,
+ MMA8450_CTRL_REG4,
+ MMA8450_CTRL_REG5,
+
+ MMA8450_OFF_X,
+ MMA8450_OFF_Y,
+ MMA8450_OFF_Z,
+
+ MMA8450_REG_END,
+};
+
+enum {
+ MODE_STANDBY,
+ MODE_2G,
+ MODE_4G,
+ MODE_8G,
+};
+
+/* mma8450 status */
+struct mma8450_status {
+ u8 mode;
+ u8 ctl_reg2;
+ u8 ctl_reg1;
+};
+
+static struct mma8450_status mma_status = {
+ .mode = 0,
+ .ctl_reg2 = 0,
+ .ctl_reg1 = 0
+};
+
+static struct device *hwmon_dev;
+static struct i2c_client *mma8450_i2c_client;
+static struct input_polled_dev *mma8450_idev;
+
+/*
+ * Initialization function
+ */
+static int mma8450_init_client(struct i2c_client *client)
+{
+ int result;
+
+ mma_status.mode = MODE_2G;
+
+ result = i2c_smbus_write_byte_data(client, MMA8450_XYZ_DATA_CFG, 0x07);
+ assert(result == 0);
+
+ result =
+ i2c_smbus_write_byte_data(client, MMA8450_CTRL_REG1,
+ mma_status.mode);
+ assert(result == 0);
+
+ mdelay(MODE_CHANGE_DELAY_MS);
+
+ return result;
+}
+
+/*
+ * read sensor data from mma8450
+ */
+static int mma8450_read_data(short *x, short *y, short *z)
+{
+ u8 tmp_data[7];
+
+ if (i2c_smbus_read_i2c_block_data
+ (mma8450_i2c_client, MMA8450_OUT_X_LSB, 7, tmp_data) < 7) {
+ dev_err(&mma8450_i2c_client->dev, "i2c block read failed\n");
+ return -3;
+ }
+
+ *x = ((tmp_data[1] << 8) & 0xff00) | ((tmp_data[0] << 4) & 0x00f0);
+ *y = ((tmp_data[3] << 8) & 0xff00) | ((tmp_data[2] << 4) & 0x00f0);
+ *z = ((tmp_data[5] << 8) & 0xff00) | ((tmp_data[4] << 4) & 0x00f0);
+
+ *x = (short)(*x) >> 4;
+ *y = (short)(*y) >> 4;
+ *z = (short)(*z) >> 4;
+
+ if (mma_status.mode == MODE_4G) {
+ (*x) = (*x) << 1;
+ (*y) = (*y) << 1;
+ (*z) = (*z) << 1;
+ } else if (mma_status.mode == MODE_8G) {
+ (*x) = (*x) << 2;
+ (*y) = (*y) << 2;
+ (*z) = (*z) << 2;
+ }
+
+ return 0;
+}
+
+static void report_abs(void)
+{
+ short x, y, z;
+ int result;
+
+ do {
+ result =
+ i2c_smbus_read_byte_data(mma8450_i2c_client,
+ MMA8450_STATUS3);
+ } while (!(result & 0x08)); /* wait for new data */
+
+ if (mma8450_read_data(&x, &y, &z) != 0)
+ return;
+
+ input_report_abs(mma8450_idev->input, ABS_X, x);
+ input_report_abs(mma8450_idev->input, ABS_Y, y);
+ input_report_abs(mma8450_idev->input, ABS_Z, z);
+ input_sync(mma8450_idev->input);
+}
+
+static void mma8450_dev_poll(struct input_polled_dev *dev)
+{
+ report_abs();
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static int __devinit mma8450_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int result;
+ struct i2c_adapter *adapter;
+ struct input_dev *idev;
+
+ mma8450_i2c_client = client;
+ adapter = to_i2c_adapter(client->dev.parent);
+
+ result = i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA);
+ assert(result);
+
+ printk(KERN_INFO "check mma8450 chip ID\n");
+ result = i2c_smbus_read_byte_data(client, MMA8450_WHO_AM_I);
+
+ if (MMA8450_ID != (result)) {
+ dev_err(&client->dev,
+ "read chip ID 0x%x is not equal to 0x%x!\n", result,
+ MMA8450_ID);
+ printk(KERN_INFO "read chip ID failed\n");
+ result = -EINVAL;
+ goto err_detach_client;
+ }
+
+ /* Initialize the MMA8450 chip */
+ result = mma8450_init_client(client);
+ assert(result == 0);
+
+ hwmon_dev = hwmon_device_register(&client->dev);
+ assert(!(IS_ERR(hwmon_dev)));
+
+ dev_info(&client->dev, "build time %s %s\n", __DATE__, __TIME__);
+
+ /*input poll device register */
+ mma8450_idev = input_allocate_polled_device();
+ if (!mma8450_idev) {
+ dev_err(&client->dev, "alloc poll device failed!\n");
+ result = -ENOMEM;
+ return result;
+ }
+ mma8450_idev->poll = mma8450_dev_poll;
+ mma8450_idev->poll_interval = POLL_INTERVAL;
+ idev = mma8450_idev->input;
+ idev->name = MMA8450_DRV_NAME;
+ idev->id.bustype = BUS_I2C;
+ idev->dev.parent = &client->dev;
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+
+ input_set_abs_params(idev, ABS_X, -8192, 8191, INPUT_FUZZ, INPUT_FLAT);
+ input_set_abs_params(idev, ABS_Y, -8192, 8191, INPUT_FUZZ, INPUT_FLAT);
+ input_set_abs_params(idev, ABS_Z, -8192, 8191, INPUT_FUZZ, INPUT_FLAT);
+ result = input_register_polled_device(mma8450_idev);
+ if (result) {
+ dev_err(&client->dev, "register poll device failed!\n");
+ return result;
+ }
+
+ return result;
+
+err_detach_client:
+ return result;
+}
+
+static int __devexit mma8450_remove(struct i2c_client *client)
+{
+ int result;
+ mma_status.ctl_reg1 =
+ i2c_smbus_read_byte_data(client, MMA8450_CTRL_REG1);
+ result =
+ i2c_smbus_write_byte_data(client, MMA8450_CTRL_REG1,
+ mma_status.ctl_reg1 & 0xFC);
+ assert(result == 0);
+
+ hwmon_device_unregister(hwmon_dev);
+
+ return result;
+}
+
+static int mma8450_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ int result;
+ mma_status.ctl_reg1 =
+ i2c_smbus_read_byte_data(client, MMA8450_CTRL_REG1);
+ result =
+ i2c_smbus_write_byte_data(client, MMA8450_CTRL_REG1,
+ mma_status.ctl_reg1 & 0xFC);
+ assert(result == 0);
+ return result;
+}
+
+static int mma8450_resume(struct i2c_client *client)
+{
+ int result;
+ result =
+ i2c_smbus_write_byte_data(client, MMA8450_CTRL_REG1,
+ mma_status.mode);
+ assert(result == 0);
+ return result;
+}
+
+static const struct i2c_device_id mma8450_id[] = {
+ {MMA8450_DRV_NAME, 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, mma8450_id);
+
+static struct i2c_driver mma8450_driver = {
+ .driver = {
+ .name = MMA8450_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .suspend = mma8450_suspend,
+ .resume = mma8450_resume,
+ .probe = mma8450_probe,
+ .remove = __devexit_p(mma8450_remove),
+ .id_table = mma8450_id,
+};
+
+static int __init mma8450_init(void)
+{
+ /* register driver */
+ int res;
+
+ res = i2c_add_driver(&mma8450_driver);
+ if (res < 0) {
+ printk(KERN_INFO "add mma8450 i2c driver failed\n");
+ return -ENODEV;
+ }
+ printk(KERN_INFO "add mma8450 i2c driver\n");
+
+ return res;
+}
+
+static void __exit mma8450_exit(void)
+{
+ printk(KERN_INFO "remove mma8450 i2c driver.\n");
+ i2c_del_driver(&mma8450_driver);
+}
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MMA8450 3-Axis Orientation/Motion Detection Sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(mma8450_init);
+module_exit(mma8450_exit);
diff --git a/drivers/hwmon/mxc_mma8451.c b/drivers/hwmon/mxc_mma8451.c
new file mode 100644
index 000000000000..901be5cedb37
--- /dev/null
+++ b/drivers/hwmon/mxc_mma8451.c
@@ -0,0 +1,371 @@
+/*
+ * mma8451.c - Linux kernel modules for 3-Axis Orientation/Motion
+ * Detection Sensor
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/input-polldev.h>
+
+/*
+ * Defines
+ */
+#define assert(expr)\
+ if (!(expr)) {\
+ printk(KERN_ERR "Assertion failed! %s,%d,%s,%s\n",\
+ __FILE__, __LINE__, __func__, #expr);\
+ }
+
+#define MMA8451_DRV_NAME "mma8451"
+#define MMA8451_I2C_ADDR 0x1C
+#define MMA8451_ID 0x1A
+
+#define POLL_INTERVAL 100
+#define INPUT_FUZZ 32
+#define INPUT_FLAT 32
+#define MODE_CHANGE_DELAY_MS 100
+
+/* register enum for mma8451 registers */
+enum {
+ MMA8451_STATUS = 0x00,
+ MMA8451_OUT_X_MSB,
+ MMA8451_OUT_X_LSB,
+ MMA8451_OUT_Y_MSB,
+ MMA8451_OUT_Y_LSB,
+ MMA8451_OUT_Z_MSB,
+ MMA8451_OUT_Z_LSB,
+
+ MMA8451_F_SETUP = 0x09,
+ MMA8451_TRIG_CFG,
+ MMA8451_SYSMOD,
+ MMA8451_INT_SOURCE,
+ MMA8451_WHO_AM_I,
+ MMA8451_XYZ_DATA_CFG,
+ MMA8451_HP_FILTER_CUTOFF,
+
+ MMA8451_PL_STATUS,
+ MMA8451_PL_CFG,
+ MMA8451_PL_COUNT,
+ MMA8451_PL_BF_ZCOMP,
+ MMA8451_P_L_THS_REG,
+
+ MMA8451_FF_MT_CFG,
+ MMA8451_FF_MT_SRC,
+ MMA8451_FF_MT_THS,
+ MMA8451_FF_MT_COUNT,
+
+ MMA8451_TRANSIENT_CFG = 0x1D,
+ MMA8451_TRANSIENT_SRC,
+ MMA8451_TRANSIENT_THS,
+ MMA8451_TRANSIENT_COUNT,
+
+ MMA8451_PULSE_CFG,
+ MMA8451_PULSE_SRC,
+ MMA8451_PULSE_THSX,
+ MMA8451_PULSE_THSY,
+ MMA8451_PULSE_THSZ,
+ MMA8451_PULSE_TMLT,
+ MMA8451_PULSE_LTCY,
+ MMA8451_PULSE_WIND,
+
+ MMA8451_ASLP_COUNT,
+ MMA8451_CTRL_REG1,
+ MMA8451_CTRL_REG2,
+ MMA8451_CTRL_REG3,
+ MMA8451_CTRL_REG4,
+ MMA8451_CTRL_REG5,
+
+ MMA8451_OFF_X,
+ MMA8451_OFF_Y,
+ MMA8451_OFF_Z,
+
+ MMA8451_REG_END,
+};
+
+enum {
+ MODE_2G = 0,
+ MODE_4G,
+ MODE_8G,
+};
+
+/* mma8451 status */
+struct mma8451_status {
+ u8 mode;
+ u8 ctl_reg1;
+};
+
+static struct mma8451_status mma_status = {
+ .mode = 0,
+ .ctl_reg1 = 0
+};
+
+static struct input_polled_dev *mma8451_idev;
+static struct device *hwmon_dev;
+static int test_test_mode = 1;
+static struct i2c_client *mma8451_i2c_client;
+
+/***************************************************************
+ *
+ * Initialization function
+ *
+ **************************************************************/
+static int mma8451_init_client(struct i2c_client *client)
+{
+ int result;
+
+ mma_status.ctl_reg1 = 0x00;
+ result =
+ i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
+ mma_status.ctl_reg1);
+ assert(result == 0);
+
+ mma_status.mode = MODE_2G;
+ result =
+ i2c_smbus_write_byte_data(client, MMA8451_XYZ_DATA_CFG,
+ mma_status.mode);
+ assert(result == 0);
+
+ mma_status.ctl_reg1 |= 0x01;
+ result =
+ i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
+ mma_status.ctl_reg1);
+ assert(result == 0);
+
+ mdelay(MODE_CHANGE_DELAY_MS);
+
+ return result;
+}
+
+/***************************************************************
+*
+* read sensor data from mma8451
+*
+***************************************************************/
+static int mma8451_read_data(short *x, short *y, short *z)
+{
+ u8 tmp_data[7];
+
+ if (i2c_smbus_read_i2c_block_data
+ (mma8451_i2c_client, MMA8451_OUT_X_MSB, 7, tmp_data) < 7) {
+ dev_err(&mma8451_i2c_client->dev, "i2c block read failed\n");
+ return -3;
+ }
+
+ *x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1];
+ *y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3];
+ *z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5];
+
+ *x = (short)(*x) >> 2;
+ *y = (short)(*y) >> 2;
+ *z = (short)(*z) >> 2;
+
+ if (mma_status.mode == MODE_4G) {
+ (*x) = (*x) << 1;
+ (*y) = (*y) << 1;
+ (*z) = (*z) << 1;
+ } else if (mma_status.mode == MODE_8G) {
+ (*x) = (*x) << 2;
+ (*y) = (*y) << 2;
+ (*z) = (*z) << 2;
+ }
+
+ return 0;
+}
+
+static void report_abs(void)
+{
+ short x, y, z;
+ int result;
+
+ do {
+ result =
+ i2c_smbus_read_byte_data(mma8451_i2c_client,
+ MMA8451_STATUS);
+ } while (!(result & 0x08)); /* wait for new data */
+
+ if (mma8451_read_data(&x, &y, &z) != 0)
+ return;
+
+ input_report_abs(mma8451_idev->input, ABS_X, x);
+ input_report_abs(mma8451_idev->input, ABS_Y, y);
+ input_report_abs(mma8451_idev->input, ABS_Z, z);
+ input_sync(mma8451_idev->input);
+}
+
+static void mma8451_dev_poll(struct input_polled_dev *dev)
+{
+ report_abs();
+}
+
+static int __devinit mma8451_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int result;
+ mma8451_i2c_client = client;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+
+ struct input_dev *idev;
+
+ result = i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA);
+ assert(result);
+
+ printk(KERN_INFO "check mma8451 chip ID\n");
+ result = i2c_smbus_read_byte_data(client, MMA8451_WHO_AM_I);
+
+ if (MMA8451_ID != result) {
+ dev_err(&client->dev,
+ "read chip ID 0x%x is not equal to 0x%x!\n", result,
+ MMA8451_ID);
+ printk(KERN_INFO "read chip ID failed\n");
+ result = -EINVAL;
+ goto err_detach_client;
+ }
+
+ /* Initialize the MMA8451 chip */
+ result = mma8451_init_client(client);
+ assert(result == 0);
+
+ hwmon_dev = hwmon_device_register(&client->dev);
+ assert(!(IS_ERR(hwmon_dev)));
+
+ dev_info(&client->dev, "build time %s %s\n", __DATE__, __TIME__);
+
+ /*input poll device register */
+ mma8451_idev = input_allocate_polled_device();
+ if (!mma8451_idev) {
+ dev_err(&client->dev, "alloc poll device failed!\n");
+ result = -ENOMEM;
+ return result;
+ }
+ mma8451_idev->poll = mma8451_dev_poll;
+ mma8451_idev->poll_interval = POLL_INTERVAL;
+ idev = mma8451_idev->input;
+ idev->name = MMA8451_DRV_NAME;
+ idev->id.bustype = BUS_I2C;
+ idev->dev.parent = &client->dev;
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+
+ input_set_abs_params(idev, ABS_X, -8192, 8191, INPUT_FUZZ, INPUT_FLAT);
+ input_set_abs_params(idev, ABS_Y, -8192, 8191, INPUT_FUZZ, INPUT_FLAT);
+ input_set_abs_params(idev, ABS_Z, -8192, 8191, INPUT_FUZZ, INPUT_FLAT);
+ result = input_register_polled_device(mma8451_idev);
+ if (result) {
+ dev_err(&client->dev, "register poll device failed!\n");
+ return result;
+ }
+ return result;
+
+err_detach_client:
+ return result;
+}
+
+static int __devexit mma8451_remove(struct i2c_client *client)
+{
+ int result;
+ mma_status.ctl_reg1 =
+ i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1);
+ result =
+ i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
+ mma_status.ctl_reg1 & 0xFE);
+ assert(result == 0);
+
+ hwmon_device_unregister(hwmon_dev);
+
+ return result;
+}
+
+static int mma8451_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ int result;
+ mma_status.ctl_reg1 =
+ i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1);
+ result =
+ i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
+ mma_status.ctl_reg1 & 0xFE);
+ assert(result == 0);
+ return result;
+}
+
+static int mma8451_resume(struct i2c_client *client)
+{
+ int result;
+ result =
+ i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
+ mma_status.ctl_reg1);
+ assert(result == 0);
+ return result;
+}
+
+static const struct i2c_device_id mma8451_id[] = {
+ {MMA8451_DRV_NAME, 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, mma8451_id);
+
+static struct i2c_driver mma8451_driver = {
+ .driver = {
+ .name = MMA8451_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .suspend = mma8451_suspend,
+ .resume = mma8451_resume,
+ .probe = mma8451_probe,
+ .remove = __devexit_p(mma8451_remove),
+ .id_table = mma8451_id,
+};
+
+static int __init mma8451_init(void)
+{
+ /* register driver */
+ int res;
+
+ res = i2c_add_driver(&mma8451_driver);
+ if (res < 0) {
+ printk(KERN_INFO "add mma8451 i2c driver failed\n");
+ return -ENODEV;
+ }
+ printk(KERN_INFO "add mma8451 i2c driver\n");
+
+ return res;
+}
+
+static void __exit mma8451_exit(void)
+{
+ printk(KERN_INFO "remove mma8451 i2c driver.\n");
+ i2c_del_driver(&mma8451_driver);
+}
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MMA8451 3-Axis Orientation/Motion Detection Sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(mma8451_init);
+module_exit(mma8451_exit);