From: "Ying-Chun Liu (PaulLiu)" <paul....@linaro.org>

Add DA9052 ADC driver from Dialog.
Modify Kconfig/Makefile for DA9052 ADC driver.

Signed-off-by: Zhou Jingyu <jingyu.z...@freescale.com>
Acked-by: Lily Zhang <r58...@freescale.com>
Signed-off-by: Ying-Chun Liu (PaulLiu) <paul....@linaro.org>
---
 drivers/hwmon/Kconfig      |   10 +
 drivers/hwmon/Makefile     |    1 +
 drivers/hwmon/da9052-adc.c |  644 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 655 insertions(+), 0 deletions(-)
 create mode 100644 drivers/hwmon/da9052-adc.c

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 16db83c..ad652dd 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -39,6 +39,16 @@ config HWMON_DEBUG_CHIP
 
 comment "Native drivers"
 
+config SENSORS_DA9052
+       tristate "Dialog DA9052 HWMon"
+       depends on PMIC_DIALOG
+       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-adc.
+
 config SENSORS_ABITUGURU
        tristate "Abit uGuru (rev 1 & 2)"
        depends on X86 && DMI && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 28061cf..e640ff8 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -118,6 +118,7 @@ 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_DA9052)   += da9052-adc.o
 
 # PMBus drivers
 obj-$(CONFIG_PMBUS)            += pmbus_core.o
diff --git a/drivers/hwmon/da9052-adc.c b/drivers/hwmon/da9052-adc.c
new file mode 100644
index 0000000..57985c2
--- /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 <dc...@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 * const 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 <dc...@diasemi.com>");
+MODULE_DESCRIPTION("DA9052 ADC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
-- 
1.7.5.3


_______________________________________________
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev

Reply via email to