mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
iio: adc: cc10001: Power-up the ADC at probe time when used remotely
The ADC is typically shared with remote CPUs not running Linux. However, there is only one register to power-up/power-down. Remote CPUs aren't able to power-up the ADC, and rely in Linux doing it instead. This commit uses the adc-reserved-channels devicetree property to distinguish shared usage. In this case, the ADC is powered up at probe time. If the ADC is used only by the CPU running Linux, power-up/down at runtime, only when neeeded. Signed-off-by: Naidu Tellapati <naidu.tellapati@imgtec.com> Signed-off-by: Ezequiel Garcia <ezequiel.garcia@imgtec.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
This commit is contained in:
parent
eb2c9ce2cc
commit
ae35496230
@ -62,6 +62,7 @@ struct cc10001_adc_device {
|
|||||||
struct regulator *reg;
|
struct regulator *reg;
|
||||||
u16 *buf;
|
u16 *buf;
|
||||||
|
|
||||||
|
bool shared;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
unsigned int start_delay_ns;
|
unsigned int start_delay_ns;
|
||||||
unsigned int eoc_delay_ns;
|
unsigned int eoc_delay_ns;
|
||||||
@ -153,7 +154,8 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p)
|
|||||||
|
|
||||||
mutex_lock(&adc_dev->lock);
|
mutex_lock(&adc_dev->lock);
|
||||||
|
|
||||||
cc10001_adc_power_up(adc_dev);
|
if (!adc_dev->shared)
|
||||||
|
cc10001_adc_power_up(adc_dev);
|
||||||
|
|
||||||
/* Calculate delay step for eoc and sampled data */
|
/* Calculate delay step for eoc and sampled data */
|
||||||
delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT;
|
delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT;
|
||||||
@ -177,7 +179,8 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
cc10001_adc_power_down(adc_dev);
|
if (!adc_dev->shared)
|
||||||
|
cc10001_adc_power_down(adc_dev);
|
||||||
|
|
||||||
mutex_unlock(&adc_dev->lock);
|
mutex_unlock(&adc_dev->lock);
|
||||||
|
|
||||||
@ -196,7 +199,8 @@ static u16 cc10001_adc_read_raw_voltage(struct iio_dev *indio_dev,
|
|||||||
unsigned int delay_ns;
|
unsigned int delay_ns;
|
||||||
u16 val;
|
u16 val;
|
||||||
|
|
||||||
cc10001_adc_power_up(adc_dev);
|
if (!adc_dev->shared)
|
||||||
|
cc10001_adc_power_up(adc_dev);
|
||||||
|
|
||||||
/* Calculate delay step for eoc and sampled data */
|
/* Calculate delay step for eoc and sampled data */
|
||||||
delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT;
|
delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT;
|
||||||
@ -205,7 +209,8 @@ static u16 cc10001_adc_read_raw_voltage(struct iio_dev *indio_dev,
|
|||||||
|
|
||||||
val = cc10001_adc_poll_done(indio_dev, chan->channel, delay_ns);
|
val = cc10001_adc_poll_done(indio_dev, chan->channel, delay_ns);
|
||||||
|
|
||||||
cc10001_adc_power_down(adc_dev);
|
if (!adc_dev->shared)
|
||||||
|
cc10001_adc_power_down(adc_dev);
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@ -322,8 +327,10 @@ static int cc10001_adc_probe(struct platform_device *pdev)
|
|||||||
adc_dev = iio_priv(indio_dev);
|
adc_dev = iio_priv(indio_dev);
|
||||||
|
|
||||||
channel_map = GENMASK(CC10001_ADC_NUM_CHANNELS - 1, 0);
|
channel_map = GENMASK(CC10001_ADC_NUM_CHANNELS - 1, 0);
|
||||||
if (!of_property_read_u32(node, "adc-reserved-channels", &ret))
|
if (!of_property_read_u32(node, "adc-reserved-channels", &ret)) {
|
||||||
|
adc_dev->shared = true;
|
||||||
channel_map &= ~ret;
|
channel_map &= ~ret;
|
||||||
|
}
|
||||||
|
|
||||||
adc_dev->reg = devm_regulator_get(&pdev->dev, "vref");
|
adc_dev->reg = devm_regulator_get(&pdev->dev, "vref");
|
||||||
if (IS_ERR(adc_dev->reg))
|
if (IS_ERR(adc_dev->reg))
|
||||||
@ -368,6 +375,14 @@ static int cc10001_adc_probe(struct platform_device *pdev)
|
|||||||
adc_dev->eoc_delay_ns = NSEC_PER_SEC / adc_clk_rate;
|
adc_dev->eoc_delay_ns = NSEC_PER_SEC / adc_clk_rate;
|
||||||
adc_dev->start_delay_ns = adc_dev->eoc_delay_ns * CC10001_WAIT_CYCLES;
|
adc_dev->start_delay_ns = adc_dev->eoc_delay_ns * CC10001_WAIT_CYCLES;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is only one register to power-up/power-down the AUX ADC.
|
||||||
|
* If the ADC is shared among multiple CPUs, always power it up here.
|
||||||
|
* If the ADC is used only by the MIPS, power-up/power-down at runtime.
|
||||||
|
*/
|
||||||
|
if (adc_dev->shared)
|
||||||
|
cc10001_adc_power_up(adc_dev);
|
||||||
|
|
||||||
/* Setup the ADC channels available on the device */
|
/* Setup the ADC channels available on the device */
|
||||||
ret = cc10001_adc_channel_init(indio_dev, channel_map);
|
ret = cc10001_adc_channel_init(indio_dev, channel_map);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -402,6 +417,7 @@ static int cc10001_adc_remove(struct platform_device *pdev)
|
|||||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||||
struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
|
struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
|
||||||
|
|
||||||
|
cc10001_adc_power_down(adc_dev);
|
||||||
iio_device_unregister(indio_dev);
|
iio_device_unregister(indio_dev);
|
||||||
iio_triggered_buffer_cleanup(indio_dev);
|
iio_triggered_buffer_cleanup(indio_dev);
|
||||||
clk_disable_unprepare(adc_dev->adc_clk);
|
clk_disable_unprepare(adc_dev->adc_clk);
|
||||||
|
Loading…
Reference in New Issue
Block a user