summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gonzalez <alex.gonzalez@digi.com>2011-12-19 11:59:42 +0100
committerAlex Gonzalez <alex.gonzalez@digi.com>2011-12-19 11:59:42 +0100
commitf92cadcfab15388520fd241062d7b5618a4bee19 (patch)
treed68256c8dae63e8e5882d83d7c851c066297969c
parent02448c5ada2d2de22acd74152b69bb2a815b5f79 (diff)
ccxmx53: Add ADC chardev interface support.
A character device interface is needed for backwards compatibility with the adc_test application. Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
-rw-r--r--arch/arm/configs/imx5_ccwmx53js_defconfig83
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/da9052-adc.c253
3 files changed, 330 insertions, 16 deletions
diff --git a/arch/arm/configs/imx5_ccwmx53js_defconfig b/arch/arm/configs/imx5_ccwmx53js_defconfig
index 969437651c25..4d3d684a9baf 100644
--- a/arch/arm/configs/imx5_ccwmx53js_defconfig
+++ b/arch/arm/configs/imx5_ccwmx53js_defconfig
@@ -1105,7 +1105,88 @@ CONFIG_GPIO_SYSFS=y
# CONFIG_GENERIC_PWM is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
-# CONFIG_HWMON is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+CONFIG_SENSORS_DA9052=y
+CONFIG_SENSORS_DA9052_CHARDEV=y
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX17135 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_EMC1403 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+# CONFIG_SENSORS_MAG3110 is not set
+# CONFIG_MXC_MMA8450 is not set
+# CONFIG_MXC_MMA8451 is not set
# CONFIG_THERMAL is not set
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 735d451b4945..7bf690ec5743 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -310,6 +310,16 @@ config SENSORS_DA9052
This driver can also be built as a module. If so, the module
will be called da9052_hwmon.
+config SENSORS_DA9052_CHARDEV
+ tristate "Dialog DA9052 character device interface"
+ depends on SENSORS_DA9052
+ help
+ Say y here to access the Dialog Semiconductor DA9052 PMIC
+ via a /dev/pmic_adc char device.
+
+ 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
diff --git a/drivers/hwmon/da9052-adc.c b/drivers/hwmon/da9052-adc.c
index b8b6e88f1d2d..85472fbc8813 100644
--- a/drivers/hwmon/da9052-adc.c
+++ b/drivers/hwmon/da9052-adc.c
@@ -23,9 +23,21 @@
#include <linux/mfd/da9052/da9052.h>
#include <linux/mfd/da9052/reg.h>
#include <linux/mfd/da9052/adc.h>
+#ifdef CONFIG_SENSORS_DA9052_CHARDEV
+#include <linux/pmic_status.h>
+#include <linux/pmic_adc.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#endif
#define DRIVER_NAME "da9052-adc"
+#ifdef CONFIG_SENSORS_DA9052_CHARDEV
+static int da9052_adc_major;
+static struct class *da9052_adc_class;
+#endif
+
static const char *input_names[] = {
[DA9052_ADC_VDDOUT] = "VDDOUT",
[DA9052_ADC_ICH] = "CHARGING CURRENT",
@@ -193,21 +205,18 @@ int da9052_read_tbat_ich(struct da9052 *da9052, char *data, int channel_no)
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:
@@ -285,16 +294,12 @@ err_ssc_comm:
return -EIO;
}
-static ssize_t da9052_adc_read_start_stop(struct device *dev,
- struct device_attribute *devattr, char *buf)
+static unsigned char da9052_adc_read_start_stop_internal( struct da9052 *da9052 , int channel )
{
- 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);
+ ret = da9052_start_adc(da9052, channel);
if (ret < 0)
return ret;
@@ -322,23 +327,37 @@ static ssize_t da9052_adc_read_start_stop(struct device *dev,
return -EINVAL;
}
msg.data = 0;
- da9052_lock(priv->da9052);
- ret = priv->da9052->read(priv->da9052, &msg);
+ da9052_lock(da9052);
+ ret = da9052->read(da9052, &msg);
if (ret != 0)
goto err_ssc_comm;
- da9052_unlock(priv->da9052);
+ da9052_unlock(da9052);
- ret = da9052_stop_adc(priv->da9052, channel);
+ ret = da9052_stop_adc(da9052, channel);
if (ret < 0)
return ret;
- return sprintf(buf, "%u\n", msg.data);
+ return msg.data;
err_ssc_comm:
- da9052_unlock(priv->da9052);
+ da9052_unlock(da9052);
return ret;
}
+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);
+ int channel = to_sensor_dev_attr(devattr)->index;
+ int ret = da9052_adc_read_start_stop_internal( priv->da9052 , channel );
+
+ if( ret < 0 )
+ return ret;
+
+ return sprintf(buf, "%u\n", ret );
+}
+
static ssize_t da9052_adc_read_ich(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -571,11 +590,208 @@ static const struct attribute_group da9052_group = {
.attrs = da9052_attr,
};
+#ifdef CONFIG_SENSORS_DA9052_CHARDEV
+/*!
+ * This function implements the open method on a DA9052 ADC device.
+ *
+ * @param inode pointer on the node
+ * @param file pointer on the file
+ * @return This function returns 0.
+ */
+static int da9052_adc_open(struct inode *inode, struct file *file)
+{
+ pr_debug("da9052_adc : da9052_adc_open()\n");
+ return 0;
+}
+
+/*!
+ * This function implements the release method on a DA9052 ADC device.
+ *
+ * @param inode pointer on the node
+ * @param file pointer on the file
+ * @return This function returns 0.
+ */
+static int da9052_adc_free(struct inode *inode, struct file *file)
+{
+ pr_debug("da9052_adc : da9052_adc_free()\n");
+ return 0;
+}
+
+/*!
+ * This function implements IOCTL controls on a DA9052 ADC device.
+ *
+ * @param inode pointer on the node
+ * @param file pointer on the file
+ * @param cmd the command
+ * @param arg the parameter
+ * @return This function returns 0 if successful.
+ */
+static int da9052_adc_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ t_adc_convert_param *convert_param;
+
+ if ((_IOC_TYPE(cmd) != 'p') && (_IOC_TYPE(cmd) != 'D'))
+ return -ENOTTY;
+
+ switch (cmd) {
+ case PMIC_ADC_CONVERT:
+ if ((convert_param = kmalloc(sizeof(t_adc_convert_param),
+ GFP_KERNEL)) == NULL) {
+ return -ENOMEM;
+ }
+ if (copy_from_user(convert_param, (t_adc_convert_param *) arg,
+ sizeof(t_adc_convert_param))) {
+ kfree(convert_param);
+ return -EFAULT;
+ }
+
+ switch (convert_param->channel){
+ case DA9052_ADC_VDDOUT:
+ convert_param->result[0] =
+ da9052_adc_read_start_stop_internal(da9052_local,
+ convert_param->channel);
+ break;
+ case DA9052_ADC_ICH:
+ da9052_read_tbat_ich(da9052_local,
+ (char *)&convert_param->result[0] , convert_param->channel);
+ break;
+ case DA9052_ADC_TBAT:
+ da9052_read_tbat_ich(da9052_local,
+ (char *)&convert_param->result[0] ,
+ convert_param->channel);
+ break;
+ case DA9052_ADC_VBAT:
+ convert_param->result[0] = da9052_manual_read(da9052_local,
+ convert_param->channel);
+ break;
+ case DA9052_ADC_ADCIN4:
+ convert_param->result[0] =
+ da9052_adc_read_start_stop_internal(da9052_local,
+ convert_param->channel);
+ break;
+ case DA9052_ADC_ADCIN5:
+ convert_param->result[0] =
+ da9052_adc_read_start_stop_internal(da9052_local,
+ convert_param->channel);
+ break;
+ case DA9052_ADC_ADCIN6:
+ convert_param->result[0] =
+ da9052_adc_read_start_stop_internal(da9052_local,
+ convert_param->channel);
+ break;
+ case DA9052_ADC_TSI:
+ pr_info("TSI not availale through chardev driver.\n");
+ return -EFAULT;
+ case DA9052_ADC_TJUNC:
+ da9052_read_tjunc(da9052_local,
+ (char *)&convert_param->result[0]);
+ break;
+ case DA9052_ADC_VBBAT:
+ convert_param->result[0] = da9052_manual_read(da9052_local,
+ convert_param->channel);
+ break;
+ default:
+ pr_err("Invalid channel %d\n",convert_param->channel);
+ return -EFAULT;
+ }
+
+ if( convert_param->result[0] < 0 ){
+ kfree(convert_param);
+ return -EFAULT;
+ }
+
+ if (copy_to_user((t_adc_convert_param *) arg, convert_param,
+ sizeof(t_adc_convert_param))) {
+ kfree(convert_param);
+ return -EFAULT;
+ }
+ kfree(convert_param);
+ break;
+
+ default:
+ pr_debug("da9052_adc_ioctl: unsupported ioctl command 0x%x\n", cmd);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct file_operations da9052_adc_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = da9052_adc_ioctl,
+ .open = da9052_adc_open,
+ .release = da9052_adc_free,
+};
+
+static struct cdev da9052_adc_cdev;
+static DEVICE_ATTR(adc, 0644, da9052_adc_show_name, NULL);
+
+static int __init da9052_adc_chardev(struct platform_device *pdev)
+{
+ int ret = 0;
+ dev_t devid;
+ struct device * sdev;
+
+ if( (ret = alloc_chrdev_region(&devid, 0, 8, "pmic_adc")) < 0 ) {
+ pr_err(KERN_ERR "Unable to allocate device range for da9052_adc\n");
+ return ret;
+ }
+ da9052_adc_major = MAJOR(devid);
+ if (da9052_adc_major < 0) {
+ pr_err(KERN_ERR "Unable to get a major for pmic_adc\n");
+ ret = da9052_adc_major;
+ goto unreg_char;
+ }
+
+ cdev_init(&da9052_adc_cdev, &da9052_adc_fops);
+ ret =cdev_add(&da9052_adc_cdev, devid, 8);
+ if (ret < 0) {
+ pr_err("pmic_adc: cannot add character device\n");
+ goto unreg_char;
+ }
+
+ da9052_adc_class = class_create(THIS_MODULE, "pmic_adc");
+ if (IS_ERR(da9052_adc_class)) {
+ pr_err(KERN_ERR "Error creating pmic_adc class.\n");
+ ret = PTR_ERR(da9052_adc_class);
+ goto unreg_char;
+ }
+
+ sdev = device_create(da9052_adc_class, NULL, devid, NULL, "pmic_adc");
+ if (IS_ERR(sdev) ) {
+ pr_err(KERN_ERR "Error creating pmic_adc class device.\n");
+ ret = PTR_ERR(sdev);
+ goto cl_destroy;
+ }
+
+ ret = device_create_file(&(pdev->dev), &dev_attr_adc);
+ if (ret) {
+ pr_err("Can't create device file!\n");
+ ret = -ENODEV;
+ goto dev_destroy;
+ }
+
+ return ret;
+
+dev_destroy:
+ device_destroy(da9052_adc_class, MKDEV(da9052_adc_major, 0));
+cl_destroy:
+ class_destroy(da9052_adc_class);
+unreg_char:
+ unregister_chrdev(da9052_adc_major, "da9052_adc");
+ return ret;
+}
+#endif
+
static int __init da9052_adc_probe(struct platform_device *pdev)
{
struct da9052_adc_priv *priv;
int ret;
+#ifdef CONFIG_SENSORS_DA9052_CHARDEV
+ da9052_adc_chardev(pdev);
+#endif
+
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -625,6 +841,13 @@ static int __devexit da9052_adc_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
kfree(priv);
+#ifdef CONFIG_SENSORS_DA9052_CHARDEV
+ device_remove_file(&(pdev->dev), &dev_attr_adc);
+ device_destroy(da9052_adc_class, MKDEV(da9052_adc_major, 0));
+ class_destroy(da9052_adc_class);
+ unregister_chrdev(da9052_adc_major, "da9052_adc");
+#endif
+
return 0;
}