diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2009-08-07 11:20:34 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2009-08-07 11:20:34 +0200 |
commit | 60785ba6ff60262adfa40e62cd5ff5a372db3feb (patch) | |
tree | 702ae75275e4d9c74a2c2c064d12b905fa1abe97 | |
parent | 558096b5369b0b555cc31f1eba8ac140575676ce (diff) | |
parent | d268ffd8f3e1deceaa2f23d863aea5c2b94ad488 (diff) | |
download | linux-2.6-phytec-master.tar.gz linux-2.6-phytec-master.tar.xz |
Merge branch 'phytec-master-sha-lfu' of /ptx/work/octopus/lfu/kernel/linux-2.6-git-1 into phytec-masterHEADphytec-mastermaster
Conflicts:
drivers/mfd/Makefile
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r-- | drivers/hwmon/Kconfig | 6 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/mc13783-adc.c | 314 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/mc13783_ts.c | 113 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/mc13783-core.c | 16 | ||||
-rw-r--r-- | include/linux/mfd/mc13783-private.h | 167 | ||||
-rw-r--r-- | include/linux/mfd/mc13783.h | 5 | ||||
-rw-r--r-- | sound/arm/mc13783.c | 2 |
10 files changed, 580 insertions, 46 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 2d5016691d4..a7e34fd31cf 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1017,6 +1017,12 @@ config SENSORS_APPLESMC Say Y here if you have an applicable laptop and want to experience the awesome power of applesmc. +config SENSORS_MC13783_ADC + tristate "Freescale MC13783 ADC" + depends on MFD_MC13783 + help + Support for the ad converter on mc13783 pmic. + config HWMON_DEBUG_CHIP bool "Hardware Monitoring Chip debugging messages" default n diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index b793dce6bed..9b4e1316964 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_SENSORS_VT8231) += vt8231.o obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o +obj-$(CONFIG_SENSORS_MC13783_ADC) += mc13783-adc.o ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c new file mode 100644 index 00000000000..2f4d1890772 --- /dev/null +++ b/drivers/hwmon/mc13783-adc.c @@ -0,0 +1,314 @@ +/* + * Copyright 2004-2007 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/input.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/mutex.h> +#include <linux/completion.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/mfd/mc13783-private.h> + +#define MC13783_ADC_NAME "mc13783-adc" + +struct mc13783_adc_priv { + struct mc13783 *mc13783; + struct mutex adc_conv_lock; + unsigned int sample[4]; + struct device *hwmon_dev; + unsigned int conv_mode; + unsigned int ts_active; +}; + +/* set adc to ts interrupt mode, which generates touchscreen wakeup interrupt */ +static void inline mc13783_adc_set_ts_irq_mode(struct mc13783 *mc13783) +{ + unsigned int reg_adc0, reg_adc1; + + reg_adc0 = MC13783_ADC0_ADREFEN | MC13783_ADC0_ADREFMODE + | MC13783_ADC0_TSMOD0; + reg_adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN; + + mc13783_reg_write(mc13783, MC13783_REG_ADC_0, reg_adc0); + mc13783_reg_write(mc13783, MC13783_REG_ADC_1, reg_adc1); +} + +int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, + unsigned int channel, unsigned int *sample) +{ + unsigned int reg_adc0, reg_adc1; + int i; + struct mc13783_adc_priv *priv = platform_get_drvdata(mc13783->adc); + + mutex_lock(&priv->adc_conv_lock); + + /* set up auto incrementing anyway to make quick read */ + reg_adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; + /* enable the adc, ignore external triggering and set ASC to trigger + * conversion */ + reg_adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN + | MC13783_ADC1_ASC; + + /* setup channel number */ + if (channel > 7) + reg_adc1 |= MC13783_ADC1_ADSEL; + + switch (mode) { + case MC13783_ADC_MODE_TS: + /* enables touch screen reference mode and set touchscreen mode + * to position mode */ + reg_adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_ADREFMODE + | MC13783_ADC0_TSMOD0 | MC13783_ADC0_TSMOD1; + reg_adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; + break; + case MC13783_ADC_MODE_SINGLE_CHAN: + reg_adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; + reg_adc1 |= MC13783_ADC1_RAND; + break; + case MC13783_ADC_MODE_MULT_CHAN: + reg_adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; + break; + default: + pr_err("Unknow ADC mode\n"); + return -EINVAL; + } + + pr_debug("writing reg0: 0x%x reg1: 0x%x\n", reg_adc0, reg_adc1); + + mc13783_reg_write(priv->mc13783, MC13783_REG_ADC_0, reg_adc0); + mc13783_reg_write(priv->mc13783, MC13783_REG_ADC_1, reg_adc1); + + wait_for_completion_interruptible(&mc13783->adc_done); + + for (i = 0; i < 4; i++) + mc13783_reg_read(mc13783, MC13783_REG_ADC_2, + &sample[i]); + + if (priv->ts_active) + mc13783_adc_set_ts_irq_mode(mc13783); + + mutex_unlock(&priv->adc_conv_lock); + + return 0; +} +EXPORT_SYMBOL(mc13783_adc_do_conversion); + +void mc13783_adc_set_ts_status(struct mc13783 *mc13783, unsigned int status) +{ + struct mc13783_adc_priv *priv = platform_get_drvdata(mc13783->adc); + + priv->ts_active = status; +} +EXPORT_SYMBOL(mc13783_adc_set_ts_status); + +static ssize_t mc13783_adc_show_read_mode(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); + unsigned int mode; + const char *mode_name; + + mode = priv->conv_mode; + + if (mode == MC13783_ADC_MODE_SINGLE_CHAN) + mode_name = "Single Channel Conversion, 8 X sample / channel"; + if (mode == MC13783_ADC_MODE_MULT_CHAN) + mode_name = "Multi Channel Conversion 1 x sample / channel "; + + return sprintf(buf, "Mode: %s\n", mode_name); +} + +static ssize_t mc13783_adc_set_read_mode(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); + + unsigned long mode = 0; + + if (!strncmp(buf, "Single", 6) || !strncmp(buf, "single", 6)) + mode = MC13783_ADC_MODE_SINGLE_CHAN; + + if (!strncmp(buf, "Multi", 5) || !strncmp(buf, "multi", 5)) + mode = MC13783_ADC_MODE_MULT_CHAN; + + if (!mode) { + pr_err("unknown or reserved mode\n"); + return -EINVAL; + } + + priv->conv_mode = mode; + + return count; +} + +static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + return sprintf(buf, "mc13783_adc\n"); +} + +static ssize_t mc13783_adc_read(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + unsigned int channel = attr -> index; + unsigned int mode, res[8]; + int i, c, res_index; + + mode = priv->conv_mode; + + mc13783_adc_do_conversion(priv->mc13783, mode, channel, priv->sample); + + for (i = 0; i < 4; i++) { + res[i] = (priv->sample[i] >> 2) & 0x3ff; + res[i + 4] = (priv->sample[i] >> 14) & 0x3ff; + } + + if (mode == MC13783_ADC_MODE_SINGLE_CHAN) { + for (i = 0; i < 8; i++) { + c += sprintf(buf, "%u%s", res[i], i < 7 ? ", " : "\n"); + buf += c; + } + } + + if (mode == MC13783_ADC_MODE_MULT_CHAN) + c = sprintf(res_print, "%u\n", res[channel & 0x7]); + + return c; +} + +static struct sensor_device_attribute mc13783_adc_ctl[] = { + SENSOR_ATTR(name, S_IRUGO, mc13783_adc_show_name, NULL, 0), + SENSOR_ATTR(read_mode, S_IWUSR | S_IRUGO, + mc13783_adc_show_read_mode, mc13783_adc_set_read_mode, 0), + + SENSOR_ATTR(in0_input, S_IRUGO, mc13783_adc_read, NULL, 0), + SENSOR_ATTR(in1_input, S_IRUGO, mc13783_adc_read, NULL, 1), + SENSOR_ATTR(in2_input, S_IRUGO, mc13783_adc_read, NULL, 2), + SENSOR_ATTR(in3_input, S_IRUGO, mc13783_adc_read, NULL, 3), + SENSOR_ATTR(in4_input, S_IRUGO, mc13783_adc_read, NULL, 4), + SENSOR_ATTR(in5_input, S_IRUGO, mc13783_adc_read, NULL, 5), + SENSOR_ATTR(in6_input, S_IRUGO, mc13783_adc_read, NULL, 6), + SENSOR_ATTR(in7_input, S_IRUGO, mc13783_adc_read, NULL, 7), + SENSOR_ATTR(in8_input, S_IRUGO, mc13783_adc_read, NULL, 8), + SENSOR_ATTR(in9_input, S_IRUGO, mc13783_adc_read, NULL, 9), + SENSOR_ATTR(in10_input, S_IRUGO, mc13783_adc_read, NULL, 10), + SENSOR_ATTR(in11_input, S_IRUGO, mc13783_adc_read, NULL, 11), + SENSOR_ATTR(in12_input, S_IRUGO, mc13783_adc_read, NULL, 12), + SENSOR_ATTR(in13_input, S_IRUGO, mc13783_adc_read, NULL, 13), + SENSOR_ATTR(in14_input, S_IRUGO, mc13783_adc_read, NULL, 14), + SENSOR_ATTR(in15_input, S_IRUGO, mc13783_adc_read, NULL, 15), +}; + +static int __init mc13783_adc_probe(struct platform_device *pdev) +{ + struct mc13783_adc_priv *priv; + int ret, i; + int entries = sizeof(mc13783_adc_ctl) + / sizeof(struct sensor_device_attribute); + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->mc13783 = pdev->dev.platform_data; + priv->conv_mode = MC13783_ADC_MODE_MULT_CHAN; + + for (i = 0; i < entries; i++) { + ret = device_create_file(&pdev->dev, + &mc13783_adc_ctl[i].dev_attr); + if (ret) { + dev_err(&pdev->dev, "device_create_file failed.\n"); + goto out_err; + } + } + + priv->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(priv->hwmon_dev)) { + dev_err(&pdev->dev, "hwmon_device_register failed.\n"); + ret = PTR_ERR(priv->hwmon_dev); + goto out_err; + } + + mutex_init(&priv->adc_conv_lock); + + /* unmask adcdone interrupts */ + mc13783_set_bits(priv->mc13783, MC13783_REG_INTERRUPT_MASK_0, + MC13783_INT_MASK_ADCDONEM, 0); + + platform_set_drvdata(pdev, priv); + + return 0; + +out_err: + for (i--; i >= 0; i--) + device_remove_file(&pdev->dev, &mc13783_adc_ctl[i].dev_attr); + + kfree(priv); + + return ret; +} + +static int __devexit mc13783_adc_remove(struct platform_device *pdev) +{ + struct mc13783_ts_priv *priv = platform_get_drvdata(pdev); + int entries = sizeof(mc13783_adc_ctl) + / sizeof(struct sensor_device_attribute); + int i; + + hwmon_device_unregister(&pdev->dev); + + for (i = 0; i < entries; i++) + device_remove_file(&pdev->dev, &mc13783_adc_ctl[i].dev_attr); + + mutex_destroy(&priv->adc_conv_lock); + + kfree(priv); + + return 0; +} + +static struct platform_driver mc13783_adc_driver = { + .probe = mc13783_adc_probe, + .remove = __devexit_p(mc13783_adc_remove), + .driver = { + .owner = THIS_MODULE, + .name = MC13783_ADC_NAME, + }, +}; + +static int __init mc13783_adc_init(void) +{ + return platform_driver_register(&mc13783_adc_driver); +} + +static void __exit mc13783_adc_exit(void) +{ + platform_driver_unregister(&mc13783_adc_driver); +} + +module_init(mc13783_adc_init); +module_exit(mc13783_adc_exit); + +MODULE_DESCRIPTION("MC13783 input touchscreen driver"); +MODULE_AUTHOR("Luotao Fu, <l.fu@pengutronix.de>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 7451cf07ab6..dbe7be3b140 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -416,6 +416,7 @@ config TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_MC13783 tristate "Freescale MC13783 touchscreen input driver" depends on MFD_MC13783 + depends on SENSORS_MC13783_ADC help Say Y here if you have an Freescale MC13783 PMIC on your board and want to use its touchscreen diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c index f9653dab4e8..efce05a17e5 100644 --- a/drivers/input/touchscreen/mc13783_ts.c +++ b/drivers/input/touchscreen/mc13783_ts.c @@ -22,77 +22,92 @@ #include <linux/input.h> #include <linux/init.h> #include <linux/platform_device.h> -#include <linux/mfd/mc13783-private.h> #include <linux/delay.h> +#include <linux/mfd/mc13783-private.h> +#include <linux/mfd/mc13783.h> + +#define MC13783_TS_NAME "mc13783-ts" -#define MC13783_NAME "mc13783-ts" +static unsigned int sample_tolerance = 75; +module_param(sample_tolerance, uint, S_IRUGO); +MODULE_PARM_DESC(sample_tolerance, + "sample_tolerance: The device reads sequetial 3 values for" + "both x and y coordinates. In normal case the three values" + " should be similar to another. You can play with this value" + "if you to throw out errneous readings. default will be 75"); struct mc13783_ts_priv { struct input_dev *idev; struct mc13783 *mc13783; struct delayed_work work; + struct workqueue_struct *workq; + unsigned int sample[4]; }; -static inline void mc13783_ts_start_conversion(struct mc13783_ts_priv *priv) -{ - mc13783_reg_write(priv->mc13783, MC13783_REG_ADC_0, 0x00033c00); - mc13783_reg_write(priv->mc13783, MC13783_REG_ADC_1, 0x00300409); -} -static inline void mc13783_ts_set_irq_mode(struct mc13783_ts_priv *priv) -{ - mc13783_reg_write(priv->mc13783, MC13783_REG_ADC_0, 0x00001c00); - mc13783_reg_write(priv->mc13783, MC13783_REG_ADC_1, 0x00200001); -} - -#define TS_MIN 80 +#define TS_MIN 1 #define TS_MAX 1000 static void mc13783_ts_handler(int irq, void *data) { struct mc13783_ts_priv *priv = data; unsigned int sts; - unsigned int sample[4]; - int i; mc13783_reg_read(priv->mc13783, MC13783_REG_INTERRUPT_STATUS_0, &sts); mc13783_reg_write(priv->mc13783, MC13783_REG_INTERRUPT_STATUS_0, - sts & 0xf); + sts & MC13783_INT_STAT_TSI); - if (sts & 4) - mc13783_ts_start_conversion(priv); + if (sts & MC13783_INT_STAT_TSI) + queue_work(priv->workq, &priv->work.work); +} - if (sts & 1) { - int x, y, press = 0; - for (i = 0; i < 4; i++) - mc13783_reg_read(priv->mc13783, MC13783_REG_ADC_2, - &sample[i]); +static void mc13783_ts_report_sample(struct mc13783_ts_priv *priv) +{ + int x, x1, x2, y, y1, y2; + int press = 0; + unsigned int tol = sample_tolerance; + + x = (priv->sample[2] >> 2) & 0x3ff; + x1 = (priv->sample[0] >> 2) & 0x3ff; + x2 = (priv->sample[1] >> 2) & 0x3ff; + y = (priv->sample[3] >> 2) & 0x3ff; + y1 = (priv->sample[0] >> 14) & 0x3ff; + y2 = (priv->sample[1] >> 14) & 0x3ff; - x = (sample[2] >> 2) & 0x3ff; - y = (sample[1] >> 14) & 0x3ff; + pr_debug("mc13783_ts: x %d, x1 %d, x2 %d, y %d, y1 %d, y2 %d" + "tolerance: %d\n", + x, x1, x2, y, y1, y2, sample_tolerance); - pr_debug("mc13783_ts: x: %d y: %d\n", x, y); + if (x > TS_MIN && x < TS_MAX && y > TS_MIN && y < TS_MAX) { - if (x > TS_MIN && x < TS_MAX && y > TS_MIN && y < TS_MAX) { + if ( abs(x-x1) < tol && abs(x-x2) < tol && abs(x1-x2) < tol + && abs(y-y1) < tol && abs(y-y2) < tol && abs(y1-y2) < tol ) { press = 1; input_report_abs(priv->idev, ABS_X, x); input_report_abs(priv->idev, ABS_Y, y); - schedule_delayed_work(&priv->work, HZ / 50); } else - mc13783_ts_set_irq_mode(priv); + pr_debug("XY Reading error!\n"); - input_report_abs(priv->idev, ABS_PRESSURE, press); - input_sync(priv->idev); + queue_delayed_work(priv->workq, &priv->work, HZ / 50); } + input_report_abs(priv->idev, ABS_PRESSURE, press); + input_sync(priv->idev); } -static void mc13783_work(struct work_struct *work) +static void mc13783_ts_work(struct work_struct *work) { struct mc13783_ts_priv *priv = container_of(work, struct mc13783_ts_priv, work.work); + unsigned int mode = MC13783_ADC_MODE_TS; + unsigned int channel = 12; + int ret; - mc13783_ts_start_conversion(priv); + ret = mc13783_adc_do_conversion + (priv->mc13783, mode, channel, priv->sample); + + if (! ret) + mc13783_ts_report_sample(priv); } static int __init mc13783_ts_probe(struct platform_device *pdev) @@ -105,7 +120,7 @@ static int __init mc13783_ts_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->mc13783 = platform_get_drvdata(pdev); + priv->mc13783 = pdev->dev.platform_data; idev = input_allocate_device(); if (!idev) { @@ -114,7 +129,7 @@ static int __init mc13783_ts_probe(struct platform_device *pdev) } priv->idev = idev; - idev->name = MC13783_NAME; + idev->name = MC13783_TS_NAME; idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); idev->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | @@ -122,7 +137,7 @@ static int __init mc13783_ts_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); - ret = mc13783_register_irq(priv->mc13783, MC13783_IRQ_ADC, + ret = mc13783_register_irq(priv->mc13783, MC13783_IRQ_TS, mc13783_ts_handler, priv); if (ret) goto err_failed_irq; @@ -134,15 +149,21 @@ static int __init mc13783_ts_probe(struct platform_device *pdev) goto err_failed_register; } - mc13783_set_bits(priv->mc13783, MC13783_REG_INTERRUPT_MASK_0, 0xf, 0); + /* unmask the ts wakeup interrupt */ + mc13783_set_bits(priv->mc13783, MC13783_REG_INTERRUPT_MASK_0, + MC13783_INT_MASK_TSM, 0); + + mc13783_adc_set_ts_status(priv->mc13783, 1); - INIT_DELAYED_WORK(&priv->work, mc13783_work); - schedule_delayed_work(&priv->work, HZ / 20); + INIT_DELAYED_WORK(&priv->work, mc13783_ts_work); + + priv->workq = create_singlethread_workqueue("mc13783_ts"); + queue_delayed_work(priv->workq, &priv->work, HZ / 20); return 0; err_failed_register: - mc13783_free_irq(priv->mc13783, MC13783_IRQ_ADC); + mc13783_free_irq(priv->mc13783, MC13783_IRQ_TS); err_failed_irq: input_free_device(priv->idev); err_input_alloc: @@ -155,10 +176,16 @@ static int __devexit mc13783_ts_remove(struct platform_device *pdev) { struct mc13783_ts_priv *priv = platform_get_drvdata(pdev); - mc13783_free_irq(priv->mc13783, MC13783_IRQ_ADC); + mc13783_adc_set_ts_status(priv->mc13783, 0); + + mc13783_free_irq(priv->mc13783, MC13783_IRQ_TS); + cancel_delayed_work(&priv->work); + destroy_workqueue(priv->workq); + input_unregister_device(priv->idev); input_free_device(priv->idev); + kfree(priv); return 0; @@ -169,7 +196,7 @@ static struct platform_driver mc13783_ts_driver = { .remove = __devexit_p(mc13783_ts_remove), .driver = { .owner = THIS_MODULE, - .name = MC13783_NAME, + .name = MC13783_TS_NAME, }, }; diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 7262822855c..9633d149acd 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -46,3 +46,4 @@ obj-$(CONFIG_MFD_PCF50633) += pcf50633-core.o obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o obj-$(CONFIG_AB3100_CORE) += ab3100-core.o + diff --git a/drivers/mfd/mc13783-core.c b/drivers/mfd/mc13783-core.c index 00b1e20aba8..f8ccafeaf82 100644 --- a/drivers/mfd/mc13783-core.c +++ b/drivers/mfd/mc13783-core.c @@ -22,6 +22,7 @@ #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/completion.h> #include <linux/spi/spi.h> #include <linux/mfd/mc13783.h> #include <linux/mfd/mc13783-private.h> @@ -168,6 +169,15 @@ static void mc13783_irq_work(struct work_struct *work) { struct mc13783 *mc13783 = container_of(work, struct mc13783, work); int i; + unsigned int adc_sts; + + /* check if the adc has finished any completion */ + mc13783_reg_read(mc13783, MC13783_REG_INTERRUPT_STATUS_0, &adc_sts); + mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_0, + adc_sts & MC13783_INT_STAT_ADCDONEI); + + if (adc_sts & MC13783_INT_STAT_ADCDONEI) + complete_all(&mc13783->adc_done); for (i = 0; i < MC13783_NUM_IRQ; i++) if (mc13783->irq_handler[i].handler) @@ -230,7 +240,7 @@ static void mc13783_client_dev_register(struct mc13783 *mc13783, } (*pdev)->dev.parent = mc13783->dev; - platform_set_drvdata(*pdev, mc13783); + (*pdev)->dev.platform_data = mc13783; ret = platform_device_add(*pdev); if (ret != 0) { dev_err(mc13783->dev, "Failed to register %s: %d\n", name, ret); @@ -261,6 +271,7 @@ static int __devinit mc13783_probe(struct spi_device *spi) INIT_WORK(&mc13783->work, mc13783_irq_work); mutex_init(&mc13783->io_lock); + init_completion(&mc13783->adc_done); if (pdata && pdata->init) pdata->init(mc13783); @@ -286,6 +297,8 @@ static int __devinit mc13783_probe(struct spi_device *spi) &mc13783->codec); mc13783_client_dev_register(mc13783, "mc13783-ts", &mc13783->ts); + mc13783_client_dev_register(mc13783, "mc13783-adc", + &mc13783->adc); return 0; @@ -305,6 +318,7 @@ static int __devexit mc13783_remove(struct spi_device *spi) platform_device_unregister(mc13783->ts); platform_device_unregister(mc13783->codec); + platform_device_unregister(mc13783->adc); if (pdata && pdata->exit) pdata->exit(); diff --git a/include/linux/mfd/mc13783-private.h b/include/linux/mfd/mc13783-private.h index 5db77c863fe..b307ee82e81 100644 --- a/include/linux/mfd/mc13783-private.h +++ b/include/linux/mfd/mc13783-private.h @@ -33,9 +33,13 @@ struct mc13783_irq { }; #define MC13783_NUM_IRQ 2 -#define MC13783_IRQ_ADC 0 +#define MC13783_IRQ_TS 0 #define MC13783_IRQ_REGULATOR 1 +#define MC13783_ADC_MODE_TS 1 +#define MC13783_ADC_MODE_SINGLE_CHAN 2 +#define MC13783_ADC_MODE_MULT_CHAN 3 + struct mc13783 { int revision; struct device *dev; @@ -51,9 +55,12 @@ struct mc13783 { struct platform_device regulators[30]; struct platform_device *codec; struct platform_device *ts; + struct platform_device *rtc; + struct platform_device *adc; struct mc13783_irq irq_handler[MC13783_NUM_IRQ]; struct work_struct work; + struct completion adc_done; }; int mc13783_reg_read(struct mc13783 *, int reg_num, u32 *); @@ -131,6 +138,56 @@ int mc13783_register_irq(struct mc13783 *mc13783, int irq, /* + * Interrupt Status + */ + +#define MC13783_INT_STAT_ADCDONEI (1 << 0) +#define MC13783_INT_STAT_ADCBISDONEI (1 << 1) +#define MC13783_INT_STAT_TSI (1 << 2) +#define MC13783_INT_STAT_WHIGHI (1 << 3) +#define MC13783_INT_STAT_WLOWI (1 << 4) +#define MC13783_INT_STAT_CHGDETI (1 << 6) +#define MC13783_INT_STAT_CHGOVI (1 << 7) +#define MC13783_INT_STAT_CHGREVI (1 << 8) +#define MC13783_INT_STAT_CHGSHORTI (1 << 9) +#define MC13783_INT_STAT_CCCVI (1 << 10) +#define MC13783_INT_STAT_CHGCURRI (1 << 11) +#define MC13783_INT_STAT_BPONI (1 << 12) +#define MC13783_INT_STAT_LOBATLI (1 << 13) +#define MC13783_INT_STAT_LOBATHI (1 << 14) +#define MC13783_INT_STAT_UDPI (1 << 15) +#define MC13783_INT_STAT_USBI (1 << 16) +#define MC13783_INT_STAT_IDI (1 << 19) +#define MC13783_INT_STAT_Unused (1 << 20) +#define MC13783_INT_STAT_SE1I (1 << 21) +#define MC13783_INT_STAT_CKDETI (1 << 22) +#define MC13783_INT_STAT_UDMI (1 << 23) + +/* + * Interrup Mask + */ + +#define MC13783_INT_MASK_ADCDONEM (1 << 0) +#define MC13783_INT_MASK_ADCBISDONEM (1 << 1) +#define MC13783_INT_MASK_TSM (1 << 2) +#define MC13783_INT_MASK_WHIGHM (1 << 3) +#define MC13783_INT_MASK_WLOWM (1 << 4) +#define MC13783_INT_MASK_CHGDETM (1 << 6) +#define MC13783_INT_MASK_CHGOVM (1 << 7) +#define MC13783_INT_MASK_CHGREVM (1 << 8) +#define MC13783_INT_MASK_CHGSHORTM (1 << 9) +#define MC13783_INT_MASK_CCCVM (1 << 10) +#define MC13783_INT_MASK_CHGCURRM (1 << 11) +#define MC13783_INT_MASK_BPONM (1 << 12) +#define MC13783_INT_MASK_LOBATLM (1 << 13) +#define MC13783_INT_MASK_LOBATHM (1 << 14) +#define MC13783_INT_MASK_UDPM (1 << 15) +#define MC13783_INT_MASK_USBM (1 << 16) +#define MC13783_INT_MASK_IDM (1 << 19) +#define MC13783_INT_MASK_SE1M (1 << 21) +#define MC13783_INT_MASK_CKDETM (1 << 22) + +/* * Reg Regulator Mode 0 */ #define MC13783_REGCTRL_VAUDIO_EN (1 << 0) @@ -229,4 +286,112 @@ int mc13783_register_irq(struct mc13783 *mc13783, int irq, #define MC13783_SWCTRL_SW3_STBY (1 << 21) #define MC13783_SWCTRL_SW3_MODE (1 << 22) +/* + * ADC/Touch + */ +#define MC13783_ADC0_LICELLCON (1 << 0) +#define MC13783_ADC0_CHRGICON (1 << 1) +#define MC13783_ADC0_BATICON (1 << 2) +#define MC13783_ADC0_RTHEN (1 << 3) +#define MC13783_ADC0_DTHEN (1 << 4) +#define MC13783_ADC0_UIDEN (1 << 5) +#define MC13783_ADC0_ADOUTEN (1 << 6) +#define MC13783_ADC0_ADOUTPER (1 << 7) +#define MC13783_ADC0_ADREFEN (1 << 10) +#define MC13783_ADC0_ADREFMODE (1 << 11) +#define MC13783_ADC0_TSMOD0 (1 << 12) +#define MC13783_ADC0_TSMOD1 (1 << 13) +#define MC13783_ADC0_TSMOD2 (1 << 14) +#define MC13783_ADC0_CHRGRAWDIV (1 << 15) +#define MC13783_ADC0_ADINC1 (1 << 16) +#define MC13783_ADC0_ADINC2 (1 << 17) +#define MC13783_ADC0_WCOMP (1 << 18) +#define MC13783_ADC0_ADCBIS0 (1 << 23) + +#define MC13783_ADC1_ADEN (1 << 0) +#define MC13783_ADC1_RAND (1 << 1) +#define MC13783_ADC1_ADSEL (1 << 3) +#define MC13783_ADC1_TRIGMASK (1 << 4) +#define MC13783_ADC1_ADA10 (1 << 5) +#define MC13783_ADC1_ADA11 (1 << 6) +#define MC13783_ADC1_ADA12 (1 << 7) +#define MC13783_ADC1_ADA20 (1 << 8) +#define MC13783_ADC1_ADA21 (1 << 9) +#define MC13783_ADC1_ADA22 (1 << 10) +#define MC13783_ADC1_ATO0 (1 << 11) +#define MC13783_ADC1_ATO1 (1 << 12) +#define MC13783_ADC1_ATO2 (1 << 13) +#define MC13783_ADC1_ATO3 (1 << 14) +#define MC13783_ADC1_ATO4 (1 << 15) +#define MC13783_ADC1_ATO5 (1 << 16) +#define MC13783_ADC1_ATO6 (1 << 17) +#define MC13783_ADC1_ATO7 (1 << 18) +#define MC13783_ADC1_ATOX (1 << 19) +#define MC13783_ADC1_ASC (1 << 20) +#define MC13783_ADC1_ADTRIGIGN (1 << 21) +#define MC13783_ADC1_ADONESHOT (1 << 22) +#define MC13783_ADC1_ADCBIS1 (1 << 23) + +#define MC13783_ADC1_CHAN0_SHIFT 5 +#define MC13783_ADC1_CHAN1_SHIFT 8 + +#define MC13783_ADC2_ADD10 (1 << 2) +#define MC13783_ADC2_ADD11 (1 << 3) +#define MC13783_ADC2_ADD12 (1 << 4) +#define MC13783_ADC2_ADD13 (1 << 5) +#define MC13783_ADC2_ADD14 (1 << 6) +#define MC13783_ADC2_ADD15 (1 << 7) +#define MC13783_ADC2_ADD16 (1 << 8) +#define MC13783_ADC2_ADD17 (1 << 9) +#define MC13783_ADC2_ADD18 (1 << 10) +#define MC13783_ADC2_ADD19 (1 << 11) +#define MC13783_ADC2_ADD20 (1 << 14) +#define MC13783_ADC2_ADD21 (1 << 15) +#define MC13783_ADC2_ADD22 (1 << 16) +#define MC13783_ADC2_ADD23 (1 << 17) +#define MC13783_ADC2_ADD24 (1 << 18) +#define MC13783_ADC2_ADD25 (1 << 19) +#define MC13783_ADC2_ADD26 (1 << 20) +#define MC13783_ADC2_ADD27 (1 << 21) +#define MC13783_ADC2_ADD28 (1 << 22) +#define MC13783_ADC2_ADD29 (1 << 23) + +#define MC13783_ADC3_WHIGH0 (1 << 0) +#define MC13783_ADC3_WHIGH1 (1 << 1) +#define MC13783_ADC3_WHIGH2 (1 << 2) +#define MC13783_ADC3_WHIGH3 (1 << 3) +#define MC13783_ADC3_WHIGH4 (1 << 4) +#define MC13783_ADC3_WHIGH5 (1 << 5) +#define MC13783_ADC3_ICID0 (1 << 6) +#define MC13783_ADC3_ICID1 (1 << 7) +#define MC13783_ADC3_ICID2 (1 << 8) +#define MC13783_ADC3_WLOW0 (1 << 9) +#define MC13783_ADC3_WLOW1 (1 << 10) +#define MC13783_ADC3_WLOW2 (1 << 11) +#define MC13783_ADC3_WLOW3 (1 << 12) +#define MC13783_ADC3_WLOW4 (1 << 13) +#define MC13783_ADC3_WLOW5 (1 << 14) +#define MC13783_ADC3_ADCBIS2 (1 << 23) + +#define MC13783_ADC4_ADDBIS10 (1 << 2) +#define MC13783_ADC4_ADDBIS11 (1 << 3) +#define MC13783_ADC4_ADDBIS12 (1 << 4) +#define MC13783_ADC4_ADDBIS13 (1 << 5) +#define MC13783_ADC4_ADDBIS14 (1 << 6) +#define MC13783_ADC4_ADDBIS15 (1 << 7) +#define MC13783_ADC4_ADDBIS16 (1 << 8) +#define MC13783_ADC4_ADDBIS17 (1 << 9) +#define MC13783_ADC4_ADDBIS18 (1 << 10) +#define MC13783_ADC4_ADDBIS19 (1 << 11) +#define MC13783_ADC4_ADDBIS20 (1 << 14) +#define MC13783_ADC4_ADDBIS21 (1 << 15) +#define MC13783_ADC4_ADDBIS22 (1 << 16) +#define MC13783_ADC4_ADDBIS23 (1 << 17) +#define MC13783_ADC4_ADDBIS24 (1 << 18) +#define MC13783_ADC4_ADDBIS25 (1 << 19) +#define MC13783_ADC4_ADDBIS26 (1 << 20) +#define MC13783_ADC4_ADDBIS27 (1 << 21) +#define MC13783_ADC4_ADDBIS28 (1 << 22) +#define MC13783_ADC4_ADDBIS29 (1 << 23) + #endif diff --git a/include/linux/mfd/mc13783.h b/include/linux/mfd/mc13783.h index db4c0e8304c..968733383f1 100644 --- a/include/linux/mfd/mc13783.h +++ b/include/linux/mfd/mc13783.h @@ -11,6 +11,11 @@ struct mc13783_platform_data { int mc13783_register_regulator(struct device *, int, struct regulator_init_data *); +int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, + unsigned int channel, unsigned int *sample); + +void mc13783_adc_set_ts_status(struct mc13783 *mc13783, unsigned int status); + #define SW_SW1A 0 #define SW_SW1B 1 #define SW_SW2A 2 diff --git a/sound/arm/mc13783.c b/sound/arm/mc13783.c index a0adce8168c..be7b065d865 100644 --- a/sound/arm/mc13783.c +++ b/sound/arm/mc13783.c @@ -537,7 +537,7 @@ static int mc13783_codec_probe(struct platform_device *pdev) if (mc13783) return -EBUSY; - mc13783 = platform_get_drvdata(pdev); + mc13783 = pdev->dev.platform_data; return 0; } |