diff options
Diffstat (limited to 'drivers/iio/frequency/ad9523.c')
| -rw-r--r-- | drivers/iio/frequency/ad9523.c | 68 | 
1 files changed, 56 insertions, 12 deletions
| diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index ddb6a334ae68..f4a508107f0d 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -12,6 +12,7 @@  #include <linux/sysfs.h>  #include <linux/spi/spi.h>  #include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h>  #include <linux/err.h>  #include <linux/module.h>  #include <linux/delay.h> @@ -268,6 +269,9 @@ struct ad9523_state {  	struct regulator		*reg;  	struct ad9523_platform_data	*pdata;  	struct iio_chan_spec		ad9523_channels[AD9523_NUM_CHAN]; +	struct gpio_desc		*pwrdown_gpio; +	struct gpio_desc		*reset_gpio; +	struct gpio_desc		*sync_gpio;  	unsigned long		vcxo_freq;  	unsigned long		vco_freq; @@ -275,6 +279,15 @@ struct ad9523_state {  	unsigned char		vco_out_map[AD9523_NUM_CHAN_ALT_CLK_SRC];  	/* +	 * Lock for accessing device registers. Some operations require +	 * multiple consecutive R/W operations, during which the device +	 * shouldn't be interrupted.  The buffers are also shared across +	 * all operations so need to be protected on stand alone reads and +	 * writes. +	 */ +	struct mutex		lock; + +	/*  	 * DMA (thus cache coherency maintenance) requires the  	 * transfer buffers to live in their own cache lines.  	 */ @@ -500,6 +513,7 @@ static ssize_t ad9523_store(struct device *dev,  {  	struct iio_dev *indio_dev = dev_to_iio_dev(dev);  	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); +	struct ad9523_state *st = iio_priv(indio_dev);  	bool state;  	int ret; @@ -508,9 +522,9 @@ static ssize_t ad9523_store(struct device *dev,  		return ret;  	if (!state) -		return 0; +		return len; -	mutex_lock(&indio_dev->mlock); +	mutex_lock(&st->lock);  	switch ((u32)this_attr->address) {  	case AD9523_SYNC:  		ret = ad9523_sync(indio_dev); @@ -521,7 +535,7 @@ static ssize_t ad9523_store(struct device *dev,  	default:  		ret = -ENODEV;  	} -	mutex_unlock(&indio_dev->mlock); +	mutex_unlock(&st->lock);  	return ret ? ret : len;  } @@ -532,15 +546,16 @@ static ssize_t ad9523_show(struct device *dev,  {  	struct iio_dev *indio_dev = dev_to_iio_dev(dev);  	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); +	struct ad9523_state *st = iio_priv(indio_dev);  	int ret; -	mutex_lock(&indio_dev->mlock); +	mutex_lock(&st->lock);  	ret = ad9523_read(indio_dev, AD9523_READBACK_0);  	if (ret >= 0) {  		ret = sprintf(buf, "%d\n", !!(ret & (1 <<  			(u32)this_attr->address)));  	} -	mutex_unlock(&indio_dev->mlock); +	mutex_unlock(&st->lock);  	return ret;  } @@ -623,9 +638,9 @@ static int ad9523_read_raw(struct iio_dev *indio_dev,  	unsigned int code;  	int ret; -	mutex_lock(&indio_dev->mlock); +	mutex_lock(&st->lock);  	ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel)); -	mutex_unlock(&indio_dev->mlock); +	mutex_unlock(&st->lock);  	if (ret < 0)  		return ret; @@ -642,7 +657,7 @@ static int ad9523_read_raw(struct iio_dev *indio_dev,  		code = (AD9523_CLK_DIST_DIV_PHASE_REV(ret) * 3141592) /  			AD9523_CLK_DIST_DIV_REV(ret);  		*val = code / 1000000; -		*val2 = (code % 1000000) * 10; +		*val2 = code % 1000000;  		return IIO_VAL_INT_PLUS_MICRO;  	default:  		return -EINVAL; @@ -659,7 +674,7 @@ static int ad9523_write_raw(struct iio_dev *indio_dev,  	unsigned int reg;  	int ret, tmp, code; -	mutex_lock(&indio_dev->mlock); +	mutex_lock(&st->lock);  	ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel));  	if (ret < 0)  		goto out; @@ -705,7 +720,7 @@ static int ad9523_write_raw(struct iio_dev *indio_dev,  	ad9523_io_update(indio_dev);  out: -	mutex_unlock(&indio_dev->mlock); +	mutex_unlock(&st->lock);  	return ret;  } @@ -713,9 +728,10 @@ static int ad9523_reg_access(struct iio_dev *indio_dev,  			      unsigned int reg, unsigned int writeval,  			      unsigned int *readval)  { +	struct ad9523_state *st = iio_priv(indio_dev);  	int ret; -	mutex_lock(&indio_dev->mlock); +	mutex_lock(&st->lock);  	if (readval == NULL) {  		ret = ad9523_write(indio_dev, reg | AD9523_R1B, writeval);  		ad9523_io_update(indio_dev); @@ -728,7 +744,7 @@ static int ad9523_reg_access(struct iio_dev *indio_dev,  	}  out_unlock: -	mutex_unlock(&indio_dev->mlock); +	mutex_unlock(&st->lock);  	return ret;  } @@ -967,6 +983,8 @@ static int ad9523_probe(struct spi_device *spi)  	st = iio_priv(indio_dev); +	mutex_init(&st->lock); +  	st->reg = devm_regulator_get(&spi->dev, "vcc");  	if (!IS_ERR(st->reg)) {  		ret = regulator_enable(st->reg); @@ -974,6 +992,32 @@ static int ad9523_probe(struct spi_device *spi)  			return ret;  	} +	st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown", +		GPIOD_OUT_HIGH); +	if (IS_ERR(st->pwrdown_gpio)) { +		ret = PTR_ERR(st->pwrdown_gpio); +		goto error_disable_reg; +	} + +	st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", +		GPIOD_OUT_LOW); +	if (IS_ERR(st->reset_gpio)) { +		ret = PTR_ERR(st->reset_gpio); +		goto error_disable_reg; +	} + +	if (st->reset_gpio) { +		udelay(1); +		gpiod_direction_output(st->reset_gpio, 1); +	} + +	st->sync_gpio = devm_gpiod_get_optional(&spi->dev, "sync", +		GPIOD_OUT_HIGH); +	if (IS_ERR(st->sync_gpio)) { +		ret = PTR_ERR(st->sync_gpio); +		goto error_disable_reg; +	} +  	spi_set_drvdata(spi, indio_dev);  	st->spi = spi;  	st->pdata = pdata; |