All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jonathan Cameron <jic23@kernel.org>
To: "Heiko Stübner" <heiko@sntech.de>
Cc: knaack.h@gmx.de, lars@metafoo.de, pmeerw@pmeerw.net,
	linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-rockchip@lists.infradead.org, xxm@rock-chips.com,
	kever.yang@rock-chips.com
Subject: Re: [PATCH v3] iio: adc: rockchip_saradc: Add support iio buffers
Date: Mon, 13 Apr 2020 17:59:59 +0100	[thread overview]
Message-ID: <20200413175959.7766b9c8@archlinux> (raw)
In-Reply-To: <4304017.Osc3njyXrW@diego>

On Mon, 13 Apr 2020 18:55:12 +0200
Heiko Stübner <heiko@sntech.de> wrote:

> Hi Jonathan,
> 

Hi Heiko,

> > > +/* buffer elements are u16, timestamp needs to be 8-byte aligned */
> > > +#define SARADC_BUFFER_NUM_U16	ALIGN(SARADC_MAX_CHANNELS, 4)  
> > I may be going crazy but I think that will get you the 'start' of the
> > timestamp, not the length including it.
> > 
> > We should be seeing 24 bytes here = 12 u16s.  Sanity check the value.
> > 
> > Running through the stack of defines.
> > #define ALIGN(x, a)		__ALIGN_KERNEL((x), (a))
> > #define __ALIGN_KERNEL(x, a)		__ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
> > #define __ALIGN_KERNEL_MASK(x, mask)	(((x) + (mask)) & ~(mask))
> > 
> > ALIGN(6, 4) == __ALIGN_KERNEL(6, 4)
> >             == __ALIGN_KERNEL_MASK(6, 3)
> >             == (((6 + 3) & ~3) 
> > which is 9 with the bottom two bits masked or b1001 & b1100 = 8 not 12
> > 
> > So I think you are looking for
> > ALIGN(SARADC_MAX_CHANNELS + sizeof(u64) / sizeof(u16), 4)
> > which will be ((10 + 3) & ~3) b1101 & b1100 = 12  
> 
> hmm, getting the start of the timestamp was actually what I intended ;-)
> The dln2-adc driver did that fancy struct definition for its data. which
> I stole, see the part from blow:

Crossed emails. I realised I was being an idiot but had already clicked send :)

> 
> > > +	struct {
> > > +		u16 values[SARADC_BUFFER_NUM_U16];
> > > +		int64_t timestamp;
> > > +	} data;  
> 
> So SARADC_BUFFER_NUM really is meant to only contain the
> number of actual buffer data - I guess I should explain that out better
> in the comment. Because defining this separate makes this so much
> more readable when we're not trying to implicitly add the timestamp
> space.
> 
> And a size_of(data) for that struct then returned nicely these 24 bytes
> in my tests.
> 
> 
> > >  
> > >  struct rockchip_saradc_data {
> > > -	int				num_bits;
> > >  	const struct iio_chan_spec	*channels;
> > >  	int				num_channels;
> > >  	unsigned long			clk_rate;
> > > @@ -49,8 +56,37 @@ struct rockchip_saradc {
> > >  	struct reset_control	*reset;
> > >  	const struct rockchip_saradc_data *data;
> > >  	u16			last_val;
> > > +	const struct iio_chan_spec *last_chan;
> > >  };
> > >  
> > > +static void rockchip_saradc_power_down(struct rockchip_saradc *info)
> > > +{
> > > +	/* Clear irq & power down adc */
> > > +	writel_relaxed(0, info->regs + SARADC_CTRL);
> > > +}
> > > +
> > > +static int rockchip_saradc_conversion(struct rockchip_saradc *info,
> > > +				   struct iio_chan_spec const *chan)
> > > +{
> > > +	reinit_completion(&info->completion);
> > > +
> > > +	/* 8 clock periods as delay between power up and start cmd */
> > > +	writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC);
> > > +
> > > +	info->last_chan = chan;
> > > +
> > > +	/* Select the channel to be used and trigger conversion */
> > > +	writel(SARADC_CTRL_POWER_CTRL
> > > +			| (chan->channel & SARADC_CTRL_CHN_MASK)
> > > +			| SARADC_CTRL_IRQ_ENABLE,
> > > +		   info->regs + SARADC_CTRL);
> > > +
> > > +	if (!wait_for_completion_timeout(&info->completion, SARADC_TIMEOUT))
> > > +		return -ETIMEDOUT;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
> > >  				    struct iio_chan_spec const *chan,
> > >  				    int *val, int *val2, long mask)
> > > @@ -62,24 +98,12 @@ static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
> > >  	case IIO_CHAN_INFO_RAW:
> > >  		mutex_lock(&indio_dev->mlock);
> > >  
> > > -		reinit_completion(&info->completion);
> > > -
> > > -		/* 8 clock periods as delay between power up and start cmd */
> > > -		writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC);
> > > -
> > > -		/* Select the channel to be used and trigger conversion */
> > > -		writel(SARADC_CTRL_POWER_CTRL
> > > -				| (chan->channel & SARADC_CTRL_CHN_MASK)
> > > -				| SARADC_CTRL_IRQ_ENABLE,
> > > -		       info->regs + SARADC_CTRL);
> > > -
> > > -		if (!wait_for_completion_timeout(&info->completion,
> > > -						 SARADC_TIMEOUT)) {
> > > -			writel_relaxed(0, info->regs + SARADC_CTRL);
> > > +		ret = rockchip_saradc_conversion(info, chan);
> > > +		if (ret) {
> > > +			rockchip_saradc_power_down(info);
> > >  			mutex_unlock(&indio_dev->mlock);
> > > -			return -ETIMEDOUT;
> > > +			return ret;
> > >  		}
> > > -
> > >  		*val = info->last_val;
> > >  		mutex_unlock(&indio_dev->mlock);
> > >  		return IIO_VAL_INT;
> > > @@ -91,7 +115,7 @@ static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
> > >  		}
> > >  
> > >  		*val = ret / 1000;
> > > -		*val2 = info->data->num_bits;
> > > +		*val2 = chan->scan_type.realbits;
> > >  		return IIO_VAL_FRACTIONAL_LOG2;
> > >  	default:
> > >  		return -EINVAL;
> > > @@ -104,10 +128,9 @@ static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id)
> > >  
> > >  	/* Read value */
> > >  	info->last_val = readl_relaxed(info->regs + SARADC_DATA);
> > > -	info->last_val &= GENMASK(info->data->num_bits - 1, 0);
> > > +	info->last_val &= GENMASK(info->last_chan->scan_type.realbits - 1, 0);
> > >  
> > > -	/* Clear irq & power down adc */
> > > -	writel_relaxed(0, info->regs + SARADC_CTRL);
> > > +	rockchip_saradc_power_down(info);
> > >  
> > >  	complete(&info->completion);
> > >  
> > > @@ -118,51 +141,55 @@ static const struct iio_info rockchip_saradc_iio_info = {
> > >  	.read_raw = rockchip_saradc_read_raw,
> > >  };
> > >  
> > > -#define ADC_CHANNEL(_index, _id) {				\
> > > +#define ADC_CHANNEL(_index, _id, _res) {			\
> > >  	.type = IIO_VOLTAGE,					\
> > >  	.indexed = 1,						\
> > >  	.channel = _index,					\
> > >  	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
> > >  	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
> > >  	.datasheet_name = _id,					\
> > > +	.scan_index = _index,					\
> > > +	.scan_type = {						\
> > > +		.sign = 'u',					\
> > > +		.realbits = _res,				\
> > > +		.storagebits = 16,				\
> > > +		.endianness = IIO_LE,				\
> > > +	},							\
> > >  }
> > >  
> > >  static const struct iio_chan_spec rockchip_saradc_iio_channels[] = {
> > > -	ADC_CHANNEL(0, "adc0"),
> > > -	ADC_CHANNEL(1, "adc1"),
> > > -	ADC_CHANNEL(2, "adc2"),
> > > +	ADC_CHANNEL(0, "adc0", 10),
> > > +	ADC_CHANNEL(1, "adc1", 10),
> > > +	ADC_CHANNEL(2, "adc2", 10),
> > >  };
> > >  
> > >  static const struct rockchip_saradc_data saradc_data = {
> > > -	.num_bits = 10,
> > >  	.channels = rockchip_saradc_iio_channels,
> > >  	.num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels),
> > >  	.clk_rate = 1000000,
> > >  };
> > >  
> > >  static const struct iio_chan_spec rockchip_rk3066_tsadc_iio_channels[] = {
> > > -	ADC_CHANNEL(0, "adc0"),
> > > -	ADC_CHANNEL(1, "adc1"),
> > > +	ADC_CHANNEL(0, "adc0", 12),
> > > +	ADC_CHANNEL(1, "adc1", 12),
> > >  };
> > >  
> > >  static const struct rockchip_saradc_data rk3066_tsadc_data = {
> > > -	.num_bits = 12,
> > >  	.channels = rockchip_rk3066_tsadc_iio_channels,
> > >  	.num_channels = ARRAY_SIZE(rockchip_rk3066_tsadc_iio_channels),
> > >  	.clk_rate = 50000,
> > >  };
> > >  
> > >  static const struct iio_chan_spec rockchip_rk3399_saradc_iio_channels[] = {
> > > -	ADC_CHANNEL(0, "adc0"),
> > > -	ADC_CHANNEL(1, "adc1"),
> > > -	ADC_CHANNEL(2, "adc2"),
> > > -	ADC_CHANNEL(3, "adc3"),
> > > -	ADC_CHANNEL(4, "adc4"),
> > > -	ADC_CHANNEL(5, "adc5"),
> > > +	ADC_CHANNEL(0, "adc0", 10),
> > > +	ADC_CHANNEL(1, "adc1", 10),
> > > +	ADC_CHANNEL(2, "adc2", 10),
> > > +	ADC_CHANNEL(3, "adc3", 10),
> > > +	ADC_CHANNEL(4, "adc4", 10),
> > > +	ADC_CHANNEL(5, "adc5", 10),
> > >  };
> > >  
> > >  static const struct rockchip_saradc_data rk3399_saradc_data = {
> > > -	.num_bits = 10,
> > >  	.channels = rockchip_rk3399_saradc_iio_channels,
> > >  	.num_channels = ARRAY_SIZE(rockchip_rk3399_saradc_iio_channels),
> > >  	.clk_rate = 1000000,
> > > @@ -193,6 +220,42 @@ static void rockchip_saradc_reset_controller(struct reset_control *reset)
> > >  	reset_control_deassert(reset);
> > >  }
> > >  
> > > +static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
> > > +{
> > > +	struct iio_poll_func *pf = p;
> > > +	struct iio_dev *i_dev = pf->indio_dev;
> > > +	struct rockchip_saradc *info = iio_priv(i_dev);
> > > +	struct {
> > > +		u16 values[SARADC_BUFFER_NUM_U16];
> > > +		int64_t timestamp;
> > > +	} data;
> > > +	int ret;
> > > +	int i, j = 0;
> > > +
> > > +	mutex_lock(&i_dev->mlock);
> > > +
> > > +	for_each_set_bit(i, i_dev->active_scan_mask, i_dev->masklength) {
> > > +		const struct iio_chan_spec *chan = &i_dev->channels[i];
> > > +
> > > +		ret = rockchip_saradc_conversion(info, chan);
> > > +		if (ret) {
> > > +			rockchip_saradc_power_down(info);
> > > +			goto out;
> > > +		}
> > > +
> > > +		data.values[j] = info->last_val;
> > > +		j++;
> > > +	}
> > > +
> > > +	iio_push_to_buffers_with_timestamp(i_dev, &data, iio_get_time_ns(i_dev));
> > > +out:
> > > +	mutex_unlock(&i_dev->mlock);
> > > +
> > > +	iio_trigger_notify_done(i_dev->trig);
> > > +
> > > +	return IRQ_HANDLED;
> > > +}
> > > +
> > >  static int rockchip_saradc_probe(struct platform_device *pdev)
> > >  {
> > >  	struct rockchip_saradc *info = NULL;
> > > @@ -221,6 +284,11 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
> > >  
> > >  	info->data = match->data;
> > >  
> > > +	if (info->data->num_channels > SARADC_MAX_CHANNELS) {
> > > +		dev_err(&pdev->dev, "max channels exceeded");
> > > +		return -EINVAL;  
> > 
> > How can that happen?  Bug in the addition of a new device type?
> > If it's just paranoia against future code, perhaps add a comment to
> > say that.  
> 
> yep that is "paranoia" for the case someone adds a fancy new 20 channel
> saradc variant and forgets to adapt the constant.
> 
> I'll add a comment.
> 
> >   
> > > +	}
> > > +
> > >  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > >  	info->regs = devm_ioremap_resource(&pdev->dev, mem);
> > >  	if (IS_ERR(info->regs))
> > > @@ -315,6 +383,12 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
> > >  	indio_dev->channels = info->data->channels;
> > >  	indio_dev->num_channels = info->data->num_channels;
> > >  
> > > +	ret = devm_iio_triggered_buffer_setup(&indio_dev->dev, indio_dev, NULL,
> > > +					      rockchip_saradc_trigger_handler,
> > > +					      NULL);
> > > +	if (ret)
> > > +		goto err_clk;
> > > +  
> > 
> > Please avoid mixing an matching between device managed an unmanaged interfaces.
> > It means the driver is not 'obviously correct' and hence harder to review.
> > 
> > Two choices here.  Either use devm_add_action_or_reset to automatically
> > disable each clock + regulator in the managed release path, drop all the error
> > handling and remove (note this should be a precursor patch), or use
> > iio_triggered_buffer_setup and manually call iio_triggered_buffer_cleanup
> > in the right place in the remove function.  
> 
> I'll go with the devm_* approach, less complexity is better than adding more ;-)
> 
> 
> Heiko
> 
> > >  	ret = iio_device_register(indio_dev);
> > >  	if (ret)
> > >  		goto err_clk;  
> > 
> >   
> 
> 
> 
> 


      reply	other threads:[~2020-04-13 17:00 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-12 22:42 [PATCH v3] iio: adc: rockchip_saradc: Add support iio buffers Heiko Stuebner
2020-04-12 22:42 ` Heiko Stuebner
2020-04-13 16:44 ` Jonathan Cameron
2020-04-13 16:44   ` Jonathan Cameron
2020-04-13 16:47   ` Jonathan Cameron
2020-04-13 16:47     ` Jonathan Cameron
2020-04-13 16:55   ` Heiko Stübner
2020-04-13 16:59     ` Jonathan Cameron [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200413175959.7766b9c8@archlinux \
    --to=jic23@kernel.org \
    --cc=heiko@sntech.de \
    --cc=kever.yang@rock-chips.com \
    --cc=knaack.h@gmx.de \
    --cc=lars@metafoo.de \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rockchip@lists.infradead.org \
    --cc=pmeerw@pmeerw.net \
    --cc=xxm@rock-chips.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.