diff options
| -rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
| -rw-r--r-- | drivers/mfd/wm831x-auxadc.c | 199 | ||||
| -rw-r--r-- | drivers/mfd/wm831x-core.c | 167 | 
3 files changed, 201 insertions, 166 deletions
| diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 22a280fcb705..0889f53c8b02 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_MFD_TC6393XB)	+= tc6393xb.o tmio_core.o  obj-$(CONFIG_MFD_WM8400)	+= wm8400-core.o  wm831x-objs			:= wm831x-core.o wm831x-irq.o wm831x-otp.o +wm831x-objs			+= wm831x-auxadc.o  obj-$(CONFIG_MFD_WM831X)	+= wm831x.o  obj-$(CONFIG_MFD_WM831X_I2C)	+= wm831x-i2c.o  obj-$(CONFIG_MFD_WM831X_SPI)	+= wm831x-spi.o diff --git a/drivers/mfd/wm831x-auxadc.c b/drivers/mfd/wm831x-auxadc.c new file mode 100644 index 000000000000..2fc9531b243d --- /dev/null +++ b/drivers/mfd/wm831x-auxadc.c @@ -0,0 +1,199 @@ +/* + * wm831x-auxadc.c  --  AUXADC for Wolfson WM831x PMICs + * + * Copyright 2009-2011 Wolfson Microelectronics PLC. + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/mfd/core.h> +#include <linux/slab.h> + +#include <linux/mfd/wm831x/core.h> +#include <linux/mfd/wm831x/pdata.h> +#include <linux/mfd/wm831x/irq.h> +#include <linux/mfd/wm831x/auxadc.h> +#include <linux/mfd/wm831x/otp.h> +#include <linux/mfd/wm831x/regulator.h> + +/** + * wm831x_auxadc_read: Read a value from the WM831x AUXADC + * + * @wm831x: Device to read from. + * @input: AUXADC input to read. + */ +int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) +{ +	int ret, src, irq_masked, timeout; + +	/* Are we using the interrupt? */ +	irq_masked = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1_MASK); +	irq_masked &= WM831X_AUXADC_DATA_EINT; + +	mutex_lock(&wm831x->auxadc_lock); + +	ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, +			      WM831X_AUX_ENA, WM831X_AUX_ENA); +	if (ret < 0) { +		dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret); +		goto out; +	} + +	/* We force a single source at present */ +	src = input; +	ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE, +			       1 << src); +	if (ret < 0) { +		dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret); +		goto out; +	} + +	/* Clear any notification from a very late arriving interrupt */ +	try_wait_for_completion(&wm831x->auxadc_done); + +	ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, +			      WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA); +	if (ret < 0) { +		dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret); +		goto disable; +	} + +	if (irq_masked) { +		/* If we're not using interrupts then poll the +		 * interrupt status register */ +		timeout = 5; +		while (timeout) { +			msleep(1); + +			ret = wm831x_reg_read(wm831x, +					      WM831X_INTERRUPT_STATUS_1); +			if (ret < 0) { +				dev_err(wm831x->dev, +					"ISR 1 read failed: %d\n", ret); +				goto disable; +			} + +			/* Did it complete? */ +			if (ret & WM831X_AUXADC_DATA_EINT) { +				wm831x_reg_write(wm831x, +						 WM831X_INTERRUPT_STATUS_1, +						 WM831X_AUXADC_DATA_EINT); +				break; +			} else { +				dev_err(wm831x->dev, +					"AUXADC conversion timeout\n"); +				ret = -EBUSY; +				goto disable; +			} +		} + +		ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); +		if (ret < 0) { +			dev_err(wm831x->dev, +				"Failed to read AUXADC data: %d\n", ret); +			goto disable; +		} + +		wm831x->auxadc_data = ret; + +	} else { +		/* If we are using interrupts then wait for the +		 * interrupt to complete.  Use an extremely long +		 * timeout to handle situations with heavy load where +		 * the notification of the interrupt may be delayed by +		 * threaded IRQ handling. */ +		if (!wait_for_completion_timeout(&wm831x->auxadc_done, +						 msecs_to_jiffies(500))) { +			dev_err(wm831x->dev, "Timed out waiting for AUXADC\n"); +			ret = -EBUSY; +			goto disable; +		} +	} + +	src = ((wm831x->auxadc_data & WM831X_AUX_DATA_SRC_MASK) +	       >> WM831X_AUX_DATA_SRC_SHIFT) - 1; + +	if (src == 14) +		src = WM831X_AUX_CAL; + +	if (src != input) { +		dev_err(wm831x->dev, "Data from source %d not %d\n", +			src, input); +		ret = -EINVAL; +	} else { +		ret = wm831x->auxadc_data & WM831X_AUX_DATA_MASK; +	} + +disable: +	wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0); +out: +	mutex_unlock(&wm831x->auxadc_lock); +	return ret; +} +EXPORT_SYMBOL_GPL(wm831x_auxadc_read); + +static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data) +{ +	struct wm831x *wm831x = irq_data; +	int ret; + +	ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); +	if (ret < 0) { +		dev_err(wm831x->dev, +			"Failed to read AUXADC data: %d\n", ret); +		wm831x->auxadc_data = 0xffff; +	} else { +		wm831x->auxadc_data = ret; +	} + +	complete(&wm831x->auxadc_done); + +	return IRQ_HANDLED; +} + +/** + * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC + * + * @wm831x: Device to read from. + * @input: AUXADC input to read. + */ +int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input) +{ +	int ret; + +	ret = wm831x_auxadc_read(wm831x, input); +	if (ret < 0) +		return ret; + +	ret *= 1465; + +	return ret; +} +EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv); + +void wm831x_auxadc_init(struct wm831x *wm831x) +{ +	int ret; + +	mutex_init(&wm831x->auxadc_lock); +	init_completion(&wm831x->auxadc_done); + +	if (wm831x->irq_base) { +		ret = request_threaded_irq(wm831x->irq_base + +					   WM831X_IRQ_AUXADC_DATA, +					   NULL, wm831x_auxadc_irq, 0, +					   "auxadc", wm831x); +		if (ret < 0) +			dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n", +				ret); +	} +} diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 480abc18f9f3..772fe584f3b8 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -306,161 +306,6 @@ out:  }  EXPORT_SYMBOL_GPL(wm831x_set_bits); -/** - * wm831x_auxadc_read: Read a value from the WM831x AUXADC - * - * @wm831x: Device to read from. - * @input: AUXADC input to read. - */ -int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) -{ -	int ret, src, irq_masked, timeout; - -	/* Are we using the interrupt? */ -	irq_masked = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1_MASK); -	irq_masked &= WM831X_AUXADC_DATA_EINT; - -	mutex_lock(&wm831x->auxadc_lock); - -	ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, -			      WM831X_AUX_ENA, WM831X_AUX_ENA); -	if (ret < 0) { -		dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret); -		goto out; -	} - -	/* We force a single source at present */ -	src = input; -	ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE, -			       1 << src); -	if (ret < 0) { -		dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret); -		goto out; -	} - -	/* Clear any notification from a very late arriving interrupt */ -	try_wait_for_completion(&wm831x->auxadc_done); - -	ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, -			      WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA); -	if (ret < 0) { -		dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret); -		goto disable; -	} - -	if (irq_masked) { -		/* If we're not using interrupts then poll the -		 * interrupt status register */ -		timeout = 5; -		while (timeout) { -			msleep(1); - -			ret = wm831x_reg_read(wm831x, -					      WM831X_INTERRUPT_STATUS_1); -			if (ret < 0) { -				dev_err(wm831x->dev, -					"ISR 1 read failed: %d\n", ret); -				goto disable; -			} - -			/* Did it complete? */ -			if (ret & WM831X_AUXADC_DATA_EINT) { -				wm831x_reg_write(wm831x, -						 WM831X_INTERRUPT_STATUS_1, -						 WM831X_AUXADC_DATA_EINT); -				break; -			} else { -				dev_err(wm831x->dev, -					"AUXADC conversion timeout\n"); -				ret = -EBUSY; -				goto disable; -			} -		} - -		ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); -		if (ret < 0) { -			dev_err(wm831x->dev, -				"Failed to read AUXADC data: %d\n", ret); -			goto disable; -		} - -		wm831x->auxadc_data = ret; - -	} else { -		/* If we are using interrupts then wait for the -		 * interrupt to complete.  Use an extremely long -		 * timeout to handle situations with heavy load where -		 * the notification of the interrupt may be delayed by -		 * threaded IRQ handling. */ -		if (!wait_for_completion_timeout(&wm831x->auxadc_done, -						 msecs_to_jiffies(500))) { -			dev_err(wm831x->dev, "Timed out waiting for AUXADC\n"); -			ret = -EBUSY; -			goto disable; -		} -	} - -	src = ((wm831x->auxadc_data & WM831X_AUX_DATA_SRC_MASK) -	       >> WM831X_AUX_DATA_SRC_SHIFT) - 1; - -	if (src == 14) -		src = WM831X_AUX_CAL; - -	if (src != input) { -		dev_err(wm831x->dev, "Data from source %d not %d\n", -			src, input); -		ret = -EINVAL; -	} else { -		ret = wm831x->auxadc_data & WM831X_AUX_DATA_MASK; -	} - -disable: -	wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0); -out: -	mutex_unlock(&wm831x->auxadc_lock); -	return ret; -} -EXPORT_SYMBOL_GPL(wm831x_auxadc_read); - -static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data) -{ -	struct wm831x *wm831x = irq_data; -	int ret; - -	ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); -	if (ret < 0) { -		dev_err(wm831x->dev, -			"Failed to read AUXADC data: %d\n", ret); -		wm831x->auxadc_data = 0xffff; -	} else { -		wm831x->auxadc_data = ret; -	} - -	complete(&wm831x->auxadc_done); - -	return IRQ_HANDLED; -} - -/** - * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC - * - * @wm831x: Device to read from. - * @input: AUXADC input to read. - */ -int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input) -{ -	int ret; - -	ret = wm831x_auxadc_read(wm831x, input); -	if (ret < 0) -		return ret; - -	ret *= 1465; - -	return ret; -} -EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv); -  static struct resource wm831x_dcdc1_resources[] = {  	{  		.start = WM831X_DC1_CONTROL_1, @@ -1447,8 +1292,6 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)  	mutex_init(&wm831x->io_lock);  	mutex_init(&wm831x->key_lock); -	mutex_init(&wm831x->auxadc_lock); -	init_completion(&wm831x->auxadc_done);  	dev_set_drvdata(wm831x->dev, wm831x);  	ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID); @@ -1603,15 +1446,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)  	if (ret != 0)  		goto err; -	if (wm831x->irq_base) { -		ret = request_threaded_irq(wm831x->irq_base + -					   WM831X_IRQ_AUXADC_DATA, -					   NULL, wm831x_auxadc_irq, 0, -					   "auxadc", wm831x); -		if (ret < 0) -			dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n", -				ret); -	} +	wm831x_auxadc_init(wm831x);  	/* The core device is up, instantiate the subdevices. */  	switch (parent) { | 
